Forth и другие саморасширяющиеся системы программирования Locations of visitors to this page
Текущее время: Вт мар 19, 2024 14:57

...
Google Search
Forth-FAQ Spy Grafic

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




Начать новую тему Ответить на тему  [ Сообщений: 42 ]  На страницу 1, 2, 3  След.

Интерсна ли данная тема?
Да, безусловно. 89%  89%  [ 17 ]
Нет, полный бред. 0%  0%  [ 0 ]
Надоело! Когда же закончатся недоделки и будет рабочий проц? 11%  11%  [ 2 ]
Всего голосов : 19
Автор Сообщение
 Заголовок сообщения: И еще один 4-хбитный ФОРТ-процессор...
СообщениеДобавлено: Пн сен 22, 2008 21:42 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Новые версии фoрт-процессоров рождаются так быстро, что продолжение старой темы теряет всякий смысл.
А по сему, начинаю новую тему о старом.

Исходные предпосылки:

1. Язык VHDL для меня до сих пор является темным лесом (с редкими просветами), а по сему, для описания процессора я буду использовать старый добрый AHDL, с которым у меня проблем нету.

2. Разрядность процессора должна быть настраиваемой, поэтому первые строчки исходника:

Код:
TITLE "FORTH-CPU version 7"

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)
VARIABLE
BEGIN
END;


Величина WIDTH формально может быть любой, но для отработки схемы выбрано число 16, как достаточно разумное при имеющихся ресурсах ПЛИС.

3. Для проверки работы форт-процессора в железе используется Альтеровский КИТ: DE1 Syclone-II 2C20 В Питере эта плата весной стоила $186, и вполне доставабельна, хотя сейчас уже имеет смысл смотреть в сторону КИТ-ов на Cyclone-III.

Схему для тестирования процессора я здесь приводить пока не буду - это отдельная большая тема, которую с мешать с процессором не стоит.

4. Итак ИДЕЯ N1 - схема процессора должна быть очень простой и прозрачной для понимания. Это достигается использованием опыта прежнего "процессоростроения" и использованием наиболее удачных идей. Как показывает практика, наибольшую сложность вызывает построение декодера команд, поэтому начну именно с него, и сделаю его так, чтобы реализация всей логики досталась САПР-у, а не разработчику.
Самый простой декодер для 4-хбитного процессора, это оператор CASE. Поэтому, записываю:
Код:
CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
    WHEN 1 => -- команда 1
    WHEN 2 => -- команда 2
    WHEN 3 => -- команда 3
    WHEN 4 => -- команда 4
    WHEN 5 => -- команда 5
    WHEN 6 => -- команда 6
    WHEN 7 => -- команда 7
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
END CASE;


5. В регистр команд загружается сразу целое слово, и для того, чтобы разбить его на четверки битов используется самый простой метод - аппаратный сдвиг.

Код:
VARIABLE
    RCMD[WIDTH+3..0] : DFF;
BEGIN
    RCMD[].clk = CLK;
    IF CMD_LOAD THEN
        RCMD[] = DI[];
    ELSE
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    END IF;
END;


Вместо IF для декодера команды в процессоре используется CASE, поэтому записываем в CASE первые действия.
Здесь же надо сразу отметить появление "спец-команды" по загрузке регистра команд, которая на поверку оказывается той самой пресловутой командой NOP, которую хочется исключить, но в данном случае, смысла этого исключения нет, ибо возникнет другая проблема - а с чем же совмещать загрузку команд?

Расписываю:

Код:
CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;



особого смысла сокращать данную запись я не вижум поэтому и не буду этого делать.
Так лучше видно, что делает каждая команда. А прямым кодированием команды занимается САПР при компиляции проекта.
Кроме того, сдесь сразу видно, каким образом в регистр команд попадает следующая группа команд.
Именно для этого в регистре команд на 4 бита больше чем ширина слова, и при загрузке команды в
последнюю тетраду записываются нули, которые и обеспечивают загрузку новой команду после того,
как все предыдущие исполнены.

6. Стеки. Вписать реализацию стеков прямо в файл процессора - можно, но не нужно. Для этого в AHDL существует механизм инклюдов, поэтому просто добавляю в после строчки с TITLE:

Код:
include "stack.inc";


а в секции VARIABLE вставляю два стека:
Код:
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFF;
    TR[WIDTH-1..0] : DFF;


как видно, вместе со стеками я добавил и два регистра, которые формально являются вершинами соответствующих стеков.
TR - вершина для стека данных, PC - вершина стека возвратов. Заклинания в скобках при описании стеков - являются передачей параметров - WIDTH - ширина стека в битах, DEPTH - глубина в словах.
Синхронизация для всех элементов общая.

Итак свожу все воедино и записываю нулевой вариант TDF-файла:

Код:
TITLE "FORTH-CPU version 7"

include "stack.inc";

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)


VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFF;
    TR[WIDTH-1..0] : DFF;
    CMD[3..0] : NODE;
BEGIN
    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;

CMD[] = RCMD[3..0];

END;


Скелет процессора готов. Осталось только наполнить оператор CASE действиями, и все будет как надо!

На этом я сейчас закончу описание построения процессора. Продолжение будет в следующих постах.
А пока мне пора спать ложиться...

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


Последний раз редактировалось WingLion Ср дек 03, 2008 08:03, всего редактировалось 1 раз.

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

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Хм... а время еще детское, можно и еще пописать...
С учетом того, что начал в 20.00, можно примерно проследить, сколько надо времени на написание подобного процессора.

Итак, продолжаю.

Очевидно (не для всех, но для меня), что 16 команд для процессора мало, поэтому в декодер команд надо сразу же заложить возможность префиксов, и это в данной схеме делается очень просто:

Код:
CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 5 => -- команда 5
        RCMD[] = (B"00000000",RCMD[WIDTH-5..4]);
    WHEN 6 => -- команда 6
        RCMD[] = (B"00000000",RCMD[WIDTH-5..4]);
    WHEN 7 => -- команда 7
        RCMD[] = (B"00000000",RCMD[WIDTH-5..4]);
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;
PREF[] = RCMD[7..4];


для команд с префиксами я выбрал три кода - 5,6 и 7. Как видно, регистр команд в момент исполнения этих команд сдвигается не на 4, а на 8 бит и, таким образом из очереди исключаются четыре бита, используемых префиксами, как код префиксной команды.
Время исполнения команды с префиксом - ровно один такт, и единственное неудобство в том, что такая команда не должна быть последней в слове, иначе, префикс будет исполняться с командой 0. Впрочем это можно и использовать (иногда, если повезет).
Увеличение же длины команды - ничто против увеличения длины программы, из-за извращений которые придется делать при сокращенном наборе команд для получения нужных действий.
Для того, чтобы определиться с типами префиксов я использую предыдущую наработку (версию 6, где все было так же, но команды с префиксами не структурированы).
Итак префиксы имеют следующие типы:
PREFIX типа 5 - DROP - команды с уменьшением использования стека данных
в этот тип попадают все двухоперандные арифметико-логические команды,
а так же, с этим префиксом могут быть закодированы специальные команды загрузки спец-регистров или вывода в порты.
PREFIX типа 6 - SWAP - команды с неизменением использования стека данных
этот префикс для команд с одним опрандом
PREFIX типа 7 - DUP - команды с увеличением использования стека данных
префикс команд загрузки специальных операндов, а так же может быть использован для ввода данных из спец-портов

DROP 0, SWAP 0, DUP 0 исполняют соответствующие команды Форта, и исключительный случай с попаданием префикса на конец командного слова получает дополнительный шанс на использование.
Для команд с префиксами используются дополнительные схемы ALU5, ALU6, ALU7, которые вводятся в исходный код как инклюды:

Код:
include "alu_5.inc":
include "alu_6.inc":
include "alu_7.inc":


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

Вписываю сделанные дополнения в общий файл:

Код:
TITLE "FORTH-CPU version 7";

include "stack.inc";
include "alu_5.inc":
include "alu_6.inc":
include "alu_7.inc":

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)


VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFF;
    TR[WIDTH-1..0] : DFF;
    CMD[3..0] : NODE;
    PREF[3..0]: NODE;
    ALU5 : alu_5;
    ALU6 : alu_6;
    ALU7 : alu_7;
BEGIN
    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;

CMD[] = RCMD[3..0];

END;

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Пн сен 22, 2008 23:20 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
начинаю наполнение оператора CASE действиями. Пока без оглядки на необходимость реализации команд перехода, вызовов, возвратов, условных переходов...

1. PC и TR переопределяются как регистры с DFFE.

2. определяются действия по умолчанию:

Код:
DEFAULTS
    RStack.cmd[] = GND; -- всегда nop
    DStack.cmd[] = GND; -- всегда nop
    PC[].ena = GND;  -- PC чаще не меняется
    TR[].ena = GND;  -- TR чаще не меняется
END DEFAULTS;

    ALU5.cmd[] = PREF[]; ALU5.op1[] = TR[]; ALU5.op2[] = DStack.do[];
    ALU6.cmd[] = PREF[]; ALU6.op1[] = TR[]; ALU6.op2[] = DStack.do[];
    ALU7.cmd[] = PREF[]; ALU7.op1[] = TR[]; ALU7.op2[] = DStack.do[];



CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
        PC[] = PC[] + 1; PC[].ena = VCC;
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[];
END CASE;


А вот теперь - точно спать! :shuffle;

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


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

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
И вот, результат на сегодня:

Код:
TITLE "FORTH-CPU version 7";

include "stack.inc";
include "alu_5.inc":
include "alu_6.inc":
include "alu_7.inc":

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)


VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFFE;
    TR[WIDTH-1..0] : DFFE;
    CMD[3..0] : NODE;
    PREF[3..0]: NODE;
    ALU5 : alu_5;
    ALU6 : alu_6;
    ALU7 : alu_7;
BEGIN

DEFAULTS
    RStack.cmd[] = GND; -- всегда nop
    DStack.cmd[] = GND; -- всегда nop
    PC[].ena = GND;  -- PC не меняется
    TR[].ena = GND;  -- TR не меняется
END DEFAULTS;

    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;
    ALU5.cmd[] = PREF[]; ALU5.op1[] = TR[]; ALU5.op2[] = DStack.do[];
    ALU6.cmd[] = PREF[]; ALU6.op1[] = TR[]; ALU6.op2[] = DStack.do[];
    ALU7.cmd[] = PREF[]; ALU7.op1[] = TR[]; ALU7.op2[] = DStack.do[];

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0
        RCMD[] = DI[];
        PC[] = PC[] + 1; PC[].ena = VCC
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

   TR[] = ALU5.rez[]; TR[].ena = VCC;
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

   TR[] = ALU6.rez[]; TR[].ena = VCC;
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

   TR[] = ALU7.rez[]; TR[].ena = VCC;
    WHEN 8,9,10,11,12,13,14,15 => остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);

END CASE;

CMD[] = RCMD[3..0];

END;

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


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

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Для того, чтобы данный файл компилился, надо сделать к нему простейшие варианты стека и трех ALU:


Код:
   TITLE "Stack on LCELL";
   PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN Stack (
   CLK   : input;
   DI[WIDTH-1..0] : input;
   DO[WIDTH-1..0] : output;
   CMD[1..0]   : input;
)
VARIABLE
   REGS[DEPTH-1..0][WIDTH-1..0] : DFFE;
   CMDR[5..0]   : NODE;
BEGIN
   CASE CMD[] IS
      WHEN 0 => CMDR[] = B"000000"; -- NOP
      WHEN 1 => CMDR[] = B"111111"; -- PUSH
      WHEN 2 => CMDR[] = B"000111"; -- POP
      WHEN 3 => CMDR[] = B"000001"; -- SWAP_TOP
   END CASE;

   REGS[][].clk   = CLK;
   REGS[0][].ena   = CMDR0;
   REGS[1][].ena   = CMDR1;
   REGS[DEPTH-1..2][].ena   = CMDR2;
   DO[] = REGS[0][];

   IF CMDR3 THEN
      REGS[0][] = DI[];
   ELSE
      REGS[0][] = REGS[1][];
   END IF;
   
   IF CMDR4 THEN
      REGS[1][] = REGS[0][];
   ELSE
      REGS[1][] = REGS[2][];
   END IF;
   FOR i IN 2 TO DEPTH-2 GENERATE
   IF CMDR5 THEN
      REGS[i][] = REGS[i-1][];
   ELSE
      REGS[i][] = REGS[i+1][];
   END IF;
   END GENERATE;
   
   IF CMDR5 THEN
      REGS[DEPTH-1][] = REGS[DEPTH-2][];
   ELSE
      REGS[DEPTH-1][] = 0;
   END IF;
END;



Код:
   TITLE "ALU DROP";

PARAMETERS (
   WIDTH=16
);

SUBDESIGN alu_5 (
   op1[WIDTH-1..0]   : input;
   op2[WIDTH-1..0]   : input;
   cmd[3..0]   : input;
   res[WIDTH-1..0]   : output;
)
VARIABLE
   logic[WIDTH-1..0]   : LCELL;
BEGIN
   logic[] = op2[];
   res[] = logic[];
END;



Код:
TITLE "ALU SWAP";

PARAMETERS (
   WIDTH=16
);

SUBDESIGN alu_6 (
   op1[WIDTH-1..0]   : input;
   op2[WIDTH-1..0]   : input;
   cmd[3..0]   : input;
   res[WIDTH-1..0]   : output;
)
VARIABLE
   logic[WIDTH-1..0]   : LCELL;
BEGIN
   logic[] = op2[];
   res[] = logic[];
END;


Код:
   TITLE "ALU DUP";

PARAMETERS (
   WIDTH=16
);

SUBDESIGN alu_7 (
   op1[WIDTH-1..0]   : input;
   op2[WIDTH-1..0]   : input;
   cmd[3..0]   : input;
   res[WIDTH-1..0]   : output;
)
VARIABLE
   logic[WIDTH-1..0]   : LCELL;
BEGIN
   logic[] = op2[];
   res[] = logic[];
END;



И главный файл (с последними исправлениями):

Код:
TITLE "FORTH-CPU version 7";

include "stack.inc";
include "alu_5.inc";
include "alu_6.inc";
include "alu_7.inc";

constant nop = 0;
constant drop = 2;
constant dup = 1;
constant swap = 3;

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)
VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFFE;
    TR[WIDTH-1..0] : DFFE;
    CMD[3..0] : NODE;
    PREF[3..0]: NODE;
    ALU5 : alu_5 with(WIDTH=WIDTH);
    ALU6 : alu_6 with(WIDTH=WIDTH);
    ALU7 : alu_7 with(WIDTH=WIDTH);
BEGIN

DEFAULTS
    RStack.cmd[] = GND; -- по умолчанию nop
    DStack.cmd[] = GND; -- по умолчанию nop
    PC[].ena = GND;  -- PC не меняется
    TR[].ena = GND;  -- TR не меняется
    RD   = VCC;
    WR   = VCC;
    CS   = VCC;
END DEFAULTS;

    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;
    ALU5.cmd[] = PREF[]; ALU5.op1[] = TR[]; ALU5.op2[] = DStack.do[];
    ALU6.cmd[] = PREF[]; ALU6.op1[] = TR[]; ALU6.op2[] = DStack.do[];
    ALU7.cmd[] = PREF[]; ALU7.op1[] = TR[]; ALU7.op2[] = DStack.do[];

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0 NOP
        RCMD[] = DI[];
        PC[] = PC[] + 1; PC[].ena = VCC;
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
      TR[] = ALU5.res[]; TR[].ena = VCC;
      DStack.di[] = TR[]; DStack.cmd[] = drop;
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
      TR[] = ALU6.res[]; TR[].ena = VCC;
      DStack.di[] = TR[]; DStack.cmd[] = dup;
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
      TR[] = ALU7.res[]; TR[].ena = VCC;
      DStack.di[] = TR[]; DStack.cmd[] = swap;
    WHEN 8,9,10,11,12,13,14,15 => -- остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
END CASE;

CMD[] = RCMD[3..0];
   ADR[] = PC[];
   DO[] = TR[];

END;


Вставляется все эти коды в соответствующие файлы, в Quartus-II
для стека и трех ALU сначала генерятся инклюд-файлы для AHDL (меню File -> Create/Update -> Create AHDL Include фор current file)

p.s. ночью я спал, а эти файлы добавил как проснулся (стек не писал заново, а просто скопировал из предыдущей версии, т.к. там он давно отлажен и работает, и на повтор уже сделанного время терять не хочется).
Сейчас ухожу на работу... вернусь вечерком и продолжу...

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Вт сен 23, 2008 22:40 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Итак, я продолжаю начатую тему.

Во первых, оставлю заглушки для ALU так как есть. Их можно достаточно легко наполнять операциями по мере необходимости.
Во вторых, определимся, какие операции нужны в первую очередь и какие будут появляться в программах чаще всего.

Первая необходимая команда - загрузка литерала - LIT - для ее выполнения нужно сделать следующее:

Код:
PC[] = PC[] + 1; PC[].ena = VCC;
TR[] = DI[]; TR[].ena = VCC;
DStack.di[] = TR[];
DStack.cmd[] = push;


Замечу, что адрес загружаемых данных подготовлен предыдущей операцией NOP, а здесь вычисляется адрес сладующего за литералом слова. Если в слове окажется несколько литералов подряд, то они и загрузятся подряд за несколько тактов.

Следующая необходимая команда - CALL:

Код:
PC[] = DI[]; PC[].ena = VCC;
RStack.cmd[] = push;
RStack.di[] = PC[] + 1;


И, конечно же, команда RET:

Код:
PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;

помимо этих действий в командах CALL и RET необходимо сбрасывать очередь команд. Это можно сделать как программно (занулив все команды после RET и CALL) или же аппаратно, записав:

Код:
RCMD[] = 0;


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

Например, команда CALL-LIT-RET загрузит непосредственное данное из адреса, который попадет в PC по CALL и управление тут же вернется на следующий адрес после точки вызова. Сие полезное свойство стоит оставить, поэтому принудительное зануление команд после CALL и RET не делаю.
В случае RET сие состояние дает возможность получить непосредственную команду NEXT для адресного интерпретатора:
команду RET-CALL, которая загружает в PC адрес из стека возвратов, тут же берет из него следующий адрес для загрузки в PC, a увеличеный на единицу адрес интерпретаяции возвращает в стек возвратов.

Итак, команды:

Код:
0 - NOP
1 - LIT
2 - CALL
3 - RET


Следующая необходимая команда - условный переход - IF

Код:
CASE 4=>
    IF (TR[] == 0) THEN
        PC[] = PC[] + 1;
    ELSE
        PC[] = DI[];
    END IF;
    PC[].ena = VCC;


Здесь замечу, что PC[] изменяется сразу же при любом значении в TR[], поэтому команды, непосредственно следующие за IF, в том же слове, будут исполнены независимо от исхода сравнения. Это может быть полезно для реализации, например "правильного IF", который при исполнении удаляет верхний элемент стека, т.е. это команда IF-DROP, a команда IF-NOP - оставит верхний элемент стека без изменения.

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


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

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Теперь о командах @ и !

для загрузки адреса используется действия, подобные команде call, a для следующее действие по разименованию или присвоению производится дополнительными командами, которые формально из набора выпадают, так как "теряют смысл" без предварительной подготовки. Возможно, я этого смысла просто не нашел, но для упрощения схемы я эти команды ввожу и никак не маскирую.

Код:
CASE 8 => -- @ -- call*
    PC[] = TR[]; PC[].ena = VCC;
    RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
CASE 9 => -- продолжение @ -  ret-@
    PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
    TR[] = DI[]; TR[].ena = VCC;
CASE 10 => -- ! -- call*
    PC[] = TR[]; PC[].ena = VCC;
    RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
    TR[] = DStack.do[]; TR[].ena = VCC; DRStack.cmd[] = pop;
CASE 11 => -- продолжение ! ret-!
    PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
    TR[] = DStack.do[]; TR[].ena = VCC; DRStack.cmd[] = pop;   


Лишние занятые коды, конечно не особенно приятны, но пока я их оставляю. Обойти их можно некоторым усложнением схемы и введением 5-битной внутренней команды, которая бы прямо дешифровалась из 4-хбитной команды, но я этого здесь делать не буду, так как формально две лишние команды мало что меняют, ибо есть префиксы, а с ними достаточное количество дополнительных команд.

Еще пара нужных команд - >R и R>:

Код:
CASE 12 => -- >R
    RStack.di[] = TR[]; RStack.cmd[] = push;
    TR[] = DStack.do[]; TR[].ena = VCC;
    DStack.cmd[] = pop;

CASE 13 => -- R>
    DStack.di[] = TR[]; DStack.cmd[] = push;
    TR[] = RStack.do[]; TR[].ena = VCC;
    RStack.cmd[] = pop;

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср сен 24, 2008 00:16 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Теперь свожу все дополнения в общий файл,
заодно добавляю пропущенные операции по установке сигналов WE и RD и CS для памяти:

Код:
TITLE "FORTH-CPU version 7";

include "stack.inc";
include "alu_5.inc";
include "alu_6.inc";
include "alu_7.inc";

constant nop = 0;
constant drop = 2;
constant dup = 1;
constant swap = 3;

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
)
VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFFE;
    TR[WIDTH-1..0] : DFFE;
    CMD[3..0] : NODE;
    PREF[3..0]: NODE;
    ALU5 : alu_5 with(WIDTH=WIDTH);
    ALU6 : alu_6 with(WIDTH=WIDTH);
    ALU7 : alu_7 with(WIDTH=WIDTH);
BEGIN

DEFAULTS
    RStack.cmd[] = GND; -- по умолчанию nop
    DStack.cmd[] = GND; -- по умолчанию nop
    PC[].ena = GND;  -- PC не меняется
    TR[].ena = GND;  -- TR не меняется
    RD   = VCC;
    WR   = VCC;
    CS   = VCC;
END DEFAULTS;

    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;
    ALU5.cmd[] = PREF[]; ALU5.op1[] = TR[]; ALU5.op2[] = DStack.do[];
    ALU6.cmd[] = PREF[]; ALU6.op1[] = TR[]; ALU6.op2[] = DStack.do[];
    ALU7.cmd[] = PREF[]; ALU7.op1[] = TR[]; ALU7.op2[] = DStack.do[];

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0 NOP
        RCMD[] = DI[]; RD = GND;
        PC[] = PC[] + 1; PC[].ena = VCC;
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[] + 1; PC[].ena = VCC;
        TR[] = DI[]; TR[].ena = VCC; RD = GND;
        DStack.di[] = TR[];
        DStack.cmd[] = push;
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = DI[]; PC[].ena = VCC; RD = GND;
        RStack.cmd[] = push;
        RStack.di[] = PC[] + 1;
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
   PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        IF (TR[] == 0) THEN
            PC[] = PC[] + 1;
        ELSE
            PC[] = DI[]; RD = GND;
        END IF;
        PC[].ena = VCC;
    WHEN 5 => -- команда 5
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        TR[] = ALU5.res[]; TR[].ena = VCC;
        DStack.di[] = TR[]; DStack.cmd[] = drop;
    WHEN 6 => -- команда 6
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        TR[] = ALU6.res[]; TR[].ena = VCC;
        DStack.di[] = TR[]; DStack.cmd[] = dup;
    WHEN 7 => -- команда 7
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        TR[] = ALU7.res[]; TR[].ena = VCC;
        DStack.di[] = TR[]; DStack.cmd[] = swap;
    CASE 8 => -- @ -- call*
        RCMD[] = (RCMD[WIDTH-1..4],B"1001");
        PC[] = TR[]; PC[].ena = VCC;
        RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
    CASE 9 => -- продолжение @ - ret-@
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
        TR[] = DI[]; TR[].ena = VCC; RD = GND;
    CASE 10 => -- ! -- call*
        RCMD[] = (RCMD[WIDTH-1..4],B"1011");
        PC[] = TR[]; PC[].ena = VCC;
        RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
        TR[] = DStack.do[]; TR[].ena = VCC; DRStack.cmd[] = pop;
    CASE 11 => -- продолжение ! ret-!
        WR = GND;
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
        TR[] = DStack.do[]; TR[].ena = VCC; DRStack.cmd[] = pop;
    CASE 12 => -- >R
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        RStack.di[] = TR[]; RStack.cmd[] = push;
        TR[] = DStack.do[]; TR[].ena = VCC;
        DStack.cmd[] = pop;
    CASE 13 => -- R>
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        DStack.di[] = TR[]; DStack.cmd[] = push;
        TR[] = RStack.do[]; TR[].ena = VCC;
        RStack.cmd[] = pop;
    WHEN 14,15 => -- остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
       
END CASE;

CMD[] = RCMD[3..0];
   ADR[] = PC[];
   DO[] = TR[];

END;


Что интересно, даже при занятых двух лишних кодах остались две резервные команды 14 и 15, которые вообще ничего не делают, кроме сдвига регистра команд на следующую четверку бит.

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


Последний раз редактировалось WingLion Ср сен 24, 2008 01:00, всего редактировалось 1 раз.

Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср сен 24, 2008 00:58 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
ИТАК, получившаяся система команд следующая:

0 - NOP: нет операции - "ничего не делает" загружает в регистр команд слово по адресу из PC, PC увеличивается на единицу
1 - LIT: загрузка литерала - ( --> dd) загружает в регистр TR слово по адресу из PC, PC увеличивается на единицу
2 - CALL: вызов подпрограммы по непосредственному адресу - PC+1 заталкивается в стек возвратов, в PC загружается слово по адресу из PC
3 - RET: возврат из подпрограммы - Выталкивается из стека возвратов последнее значение и вписывается в PC
4 - IF: условный переход ( --> ) ЕСЛИ регистр TR содержит нуль PC увеличивается на единичку (переходит на адрес следующий после адреса перехода) ИНАЧЕ в PC загружается слово по адресу из PC

5 - DROP* префикс команды типа drop - (dd2 dd1 --> dd2 ) - пока исполняет чистый DROP независимо следующего кода
6 - DUP* префикс команды типа dup - ( dd1 --> dd1 dd2 ) - пока исполняет чистый DUP независимо следующего кода
7 - SWAP* префикс команды типа swap - ( dd1 dd2 --> dd1 dd2 ) - пока исполняет чистый SWAP независимо следующего кода
8 - @ разыменование (dd --> mem) - (слово из памяти по адресу из TR записывается в TR) сначала PC запоминается в стеке возвртов, а в PC записывается адрес из TR,
принудительно устанавливается следующий исполняемый код команды - 9 для продолжения исполнения команды @
9 - ret-@ продолжение рзыменования - происходит считывание слова из адреса в PC и запись его в TR, a в PC возвращается значение из стека возвратов
чистое использование этого кода как команды - сомнительно, поэтому в будущем код будет маскирован и, возможно в чистом виде будет исполнять что-то полезное
10 - ! присводение (dd aa --> ) - (слово dd записывается в память по адресу аа) сначала сначала PC запоминается в стеке возвртов, а в PC записывается адрес из TR,
принудительно устанавливается следующий исполняемый код команды - 11 для продолжения исполнения команды !
11 - ret-! продолжение присвоения - происходит запись слова из TR в память по адресу из PC, a в PC возвращается значение из стека возвратов
чистое использование этого кода как команды - сомнительно, поэтому в будущем код будет маскирован и, возможно в чистом виде будет исполнять что-то полезное
12 - >R на-Эр - (dd -->) слово из TR заталкивается на стек возвратов, в TR записывается слово вытолкнутое из стека данных
13 - R> с-Эр - (--> dd) слово из TR заталкивается на стек данных, в TR записывается слово вытолкнутое из стека возвратов
15 - NOP* резервный код
16 - NOP* резервный код

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср сен 24, 2008 07:47 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
И еще одна ссылочка:
http://winglion.ru/Forth-CPU/fcpu7l.zip (22kb) - все файлы форт-процессора,
в том числе файлы проекта для Quartus-а.

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


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


Вернуться к началу
  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср сен 24, 2008 19:02 
Не в сети
Administrator
Administrator
Аватара пользователя

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

1. Ввожу в в схему сигнал сброса, который устанавливает PC и регистр команд в ноль.
2. Делаю исправления ошибок, обнаруженных при попытке компиляции проекта.

Проверяю работу команд процессора в симуляторе. Команды подаю вручную на входы

Изображение

1. команда 0 - NOP 5 РАЗ ПОДРЯД - ЗАГРУЗКА КОМАНДЫ - СНОВА NOP - счетчик команд увеличивается каждый такт, пока не встречается первая не-NOP команда.
2. команды 000F и FEFE - проверяется сдвиг в регистре команд и загрузка следующей команды после исполнение последовaтельности нe-NOP
3. команда 0001 - LIT - загрузка операнда - операнд AA55 агружается в TR на следующем такте после загрузки в регистр команд кода 0001
исполняется код 1, затем 0 - загрузка следующей команды без лишних ожиданий
4. команда 0002 - CALL - переход по адресу 0222 происходит на следующем такте в момент загрузки адреса перехода.
5. команда 3А11 - однословная подпрограмма с загрузкой двух слов - данных и адреса - данные записывются по адресу, после чего происходит возврат из подпрогряммы.
проверяется ход изполнения, пока адрес в PC не возврщается к точке вызова подпрограммы - на адрес 000Б
6. проверка префиксных команд - код 4657 - обнаруживается неправильная работа команды 7 - код после префикса в регистре команд надо пропустить (он используется как
команда для ALU одновременно с моментом исполнения кода 7).

Исправляю:

Код:
RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
в командах 5,6,7 заменяется на:
RCMD[] = (B"0000000",RCMD[WIDTH-1..8]);

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Ср сен 24, 2008 19:09 
Не в сети
Administrator
Administrator
Аватара пользователя

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

Код:
TITLE "FORTH-CPU version 7";

include "stack.inc";
include "alu_5.inc";
include "alu_6.inc";
include "alu_7.inc";

constant nop = 0;
constant pop = 2;
constant push = 1;
constant swap = 3;

PARAMETERS (
        WIDTH = 16,
        DEPTH = 8
);
SUBDESIGN fcpu (
        CLK : input;  -- ясное дело - синхронизация!
        DI[WIDTH-1..0] : input; -- данные, считываемые из ОЗУ
        DO[WIDTH-1..0] : output; -- данные для запппписи в ОЗУ
        ADR[WIDTH-1..0] : output; -- адрес ОЗУ
        RD,WR,CS : output; -- управляющие сигналы ОЗУ
        RESET   : input;
)
VARIABLE
    RCMD[WIDTH-1..0] : DFF;
    RStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    DStack : stack with(WIDTH=WIDTH,DEPTH=DEPTH);
    PC[WIDTH-1..0] : DFFE;
    TR[WIDTH-1..0] : DFFE;
    CMD[3..0] : NODE;
    PREF[3..0]: NODE;
    ALU5 : alu_5 with(WIDTH=WIDTH);
    ALU6 : alu_6 with(WIDTH=WIDTH);
    ALU7 : alu_7 with(WIDTH=WIDTH);
BEGIN

DEFAULTS
    RStack.cmd[] = GND; -- по умолчанию nop
    DStack.cmd[] = GND; -- по умолчанию nop
    PC[].ena = GND;  -- PC не меняется
    TR[].ena = GND;  -- TR не меняется
    RD   = VCC;
    WR   = VCC;
    CS   = VCC;
END DEFAULTS;

   (RCMD[].clrn,PC[].clrn) = DFF(RESET,CLK,,);

    RCMD[].clk = clk;
    RStack.clk = clk;
    DStack.clk = clk;
    PC[].clk = clk;
    TR[].clk = clk;
    ALU5.cmd[] = PREF[]; ALU5.op1[] = TR[]; ALU5.op2[] = DStack.do[];
    ALU6.cmd[] = PREF[]; ALU6.op1[] = TR[]; ALU6.op2[] = DStack.do[];
    ALU7.cmd[] = PREF[]; ALU7.op1[] = TR[]; ALU7.op2[] = DStack.do[];
    PREF[] = RCMD[7..4];

CASE CMD[3..0] IS
    WHEN 0 => -- команда 0 NOP
        RCMD[] = DI[]; RD = GND;
        PC[] = PC[] + 1; PC[].ena = VCC;
    WHEN 1 => -- команда 1
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = PC[] + 1; PC[].ena = VCC;
        TR[] = DI[]; TR[].ena = VCC; RD = GND;
        DStack.di[] = TR[];
        DStack.cmd[] = push;
    WHEN 2 => -- команда 2
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = DI[]; PC[].ena = VCC; RD = GND;
        RStack.cmd[] = push;
        RStack.di[] = PC[] + 1;
    WHEN 3 => -- команда 3
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
   PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
    WHEN 4 => -- команда 4
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        IF (TR[] == 0) THEN
            PC[] = PC[] + 1;
        ELSE
            PC[] = DI[]; RD = GND;
        END IF;
        PC[].ena = VCC;
    WHEN 5 => -- команда 5 DUP*
        RCMD[] = (B"00000000",RCMD[WIDTH-1..8]);
        TR[] = ALU5.res[]; TR[].ena = VCC;
       DStack.di[] = TR[]; DStack.cmd[] = push;
    WHEN 6 => -- команда 6 DROP*
        RCMD[] = (B"00000000",RCMD[WIDTH-1..8]);
        TR[] = ALU6.res[]; TR[].ena = VCC;
        DStack.di[] = TR[]; DStack.cmd[] = pop;
    WHEN 7 => -- команда 7 SWAP*
        RCMD[] = (B"00000000",RCMD[WIDTH-1..8]);
        TR[] = ALU7.res[]; TR[].ena = VCC;
        DStack.di[] = TR[]; DStack.cmd[] = swap;
    WHEN 8 => -- @ -- call*
        RCMD[] = (RCMD[WIDTH-1..4],B"1001");
        PC[] = TR[]; PC[].ena = VCC;
        RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
    WHEN 9 => -- продолжение @ - ret-@
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
        TR[] = DI[]; TR[].ena = VCC; RD = GND;
    WHEN 10 => -- ! -- call*
        RCMD[] = (RCMD[WIDTH-1..4],B"1011");
        PC[] = TR[]; PC[].ena = VCC;
        RStack.di[] = PC[]; RStack.cmd[] = push; -- сохраняется неизменное(!) значение PC
        TR[] = DStack.do[]; TR[].ena = VCC; DStack.cmd[] = pop;
    WHEN 11 => -- продолжение ! ret-!
        WR = GND;
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        PC[] = RStack.do[]; PC[].ena = VCC; RStack.cmd[] = pop;
        TR[] = DStack.do[]; TR[].ena = VCC; DStack.cmd[] = pop;
    WHEN 12 => -- >R
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        RStack.di[] = TR[]; RStack.cmd[] = push;
        TR[] = DStack.do[]; TR[].ena = VCC;
        DStack.cmd[] = pop;
    WHEN 13 => -- R>
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        DStack.di[] = TR[]; DStack.cmd[] = push;
        TR[] = RStack.do[]; TR[].ena = VCC;
        RStack.cmd[] = pop;
    WHEN 14,15 => -- остальные команды
        RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;

    CMD[] = RCMD[3..0];
   ADR[] = PC[];
   DO[] = TR[];

END;

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Чт сен 25, 2008 07:30 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Во первых, исправленый полный зип с проектом:
http://winglion.ru/Forth-CPU/fcpu7last.zip (изменения есть во всех исходных файлах! в особенности исходники ALU_i)

обновленная система команд (расширено описание команд с префиксами и сами они изменились):

Код:
0 - NOP: нет операции - "ничего не делает" загружает в регистр команд слово по адресу из PC, PC увеличивается на единицу
1 - LIT: загрузка литерала - ( --> dd) загружает в регистр TR слово по адресу из PC, PC увеличивается на единицу
2 - CALL: вызов подпрограммы по непосредственному адресу - PC+1 заталкивается в стек возвратов, в PC загружается слово по адресу из PC
3 - RET: возврат из подпрограммы - Выталкивается из стека возвратов последнее значение и вписывается в PC
4 - IF: условный переход ( --> ) ЕСЛИ регистр TR содержит нуль PC увеличивается на единичку (переходит на адрес следующий после адреса перехода) ИНАЧЕ в PC загружается слово по адресу из PC

5 - DUP* префикс команды типа dup - ( dd  --> dd2 dd1) - глубина используемого стека увеличивается
    набор команд с префиксом DUP*:
    DUP-0 -- DUP ( dd --> dd dd)
    DUP-1 -- OVER ( dd1 dd2 --> d1 dd2 dd1)
    DUP-3 -- TRUE ( dd --> dd FFFF)
    DUP-4 -- FALSE ( dd --> dd 0)
    DUP-5 -- 1 ( dd --> dd 1)
    DUP-5...15 -- зарезервированы (пока эквивалентны DUP-5)
6 - DROP* префикс команды типа dup - ( dd1 --> dd1 dd2 ) - глубина используемого стека уменьшается
    набор команд с префиксом DROP*:
    DROP-0 -- DROP ( dd2 dd1 --> dd2)
    DROP-2 -- ADD ( dd2 dd1 --> dd2+dd1)
    DROP-3 -- SUB ( dd2 dd1 --> dd2-dd1)
    DROP-4 -- MUL ( dd2 dd1 --> dd2*dd1)
    DROP-5 -- AND ( dd2 dd1 --> dd2 and dd1)
    DROP-6 -- OR ( dd2 dd1 --> dd2 or dd1)
    DROP-7 -- XOR ( dd2 dd1 --> dd2 xor dd1)
    DROP-8..15 -- зарезервированы (пока эквивалентны DROP-0)
7 - SWAP* префикс команды типа swap - ( dd1 dd2 --> dd1 dd2 ) - глубина используемого стека не меняется
    набор команд с префиксом SWAP*:
    SWAP-0 -- SWAP (dd2 dd1 --> dd1 dd2)
    SWAP-1 -- INC (dd2 dd1 --> dd2 dd1+1)
    SWAP-2 -- DEC (dd2 dd1 --> dd2 dd1-1)
    SWAP-3 -- NEG (dd2 dd1 --> dd2 - dd1)
    SWAP-4..15 -- зарезервированы (пока эквивалентны SWAP-0)
   
8 - @ разыменование (dd --> mem) - (слово из памяти по адресу из TR записывается в TR) сначала PC запоминается в стеке возвртов, а в PC записывается адрес из TR,
    принудительно устанавливается следующий исполняемый код команды - 9 для продолжения исполнения команды @
9 - ret-@ продолжение рзыменования - происходит считывание слова из адреса в PC и запись его в TR, a в PC возвращается значение из стека возвратов
    чистое использование этого кода как команды - сомнительно, поэтому в будущем код будет маскирован и, возможно в чистом виде будет исполнять что-то полезное
10 - ! присводение (dd aa --> ) - (слово dd записывается в память по адресу аа) сначала сначала PC запоминается в стеке возвртов, а в PC записывается адрес из TR,
    принудительно устанавливается следующий исполняемый код команды - 11 для продолжения исполнения команды !
11 - ret-! продолжение присвоения - происходит запись слова из TR в память по адресу из PC, a в PC возвращается значение из стека возвратов
    чистое использование этого кода как команды - сомнительно, поэтому в будущем код будет маскирован и, возможно в чистом виде будет исполнять что-то полезное
12 - >R на-Эр - (dd -->) слово из TR заталкивается на стек возвратов, в TR записывается слово вытолкнутое из стека данных
13 - R> с-Эр - (--> dd) слово из TR заталкивается на стек данных, в TR записывается слово вытолкнутое из стека возвратов
15 - NOP* резервный код
16 - NOP* резервный код

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


Вернуться к началу
 Профиль Отправить личное сообщение  
Ответить с цитатой  
 Заголовок сообщения:
СообщениеДобавлено: Чт сен 25, 2008 23:13 
Не в сети
Administrator
Administrator
Аватара пользователя

Зарегистрирован: Вт май 02, 2006 13:19
Сообщения: 3565
Откуда: St.Petersburg
Благодарил (а): 4 раз.
Поблагодарили: 72 раз.
Очередное дополнение - введена команда MOVE - код 14:

Код:
    WHEN 14 => -- MOVE
      PC[] = RStack.do[]; RStack.cmd[] = swap; PC[].ena = VCC;
      RStack.di[] = PC[] + 1;
      XR = !XR;
      IF !XR THEN
         TR[] = DI[]; TR[].ena = VCC; RD = GND;
         DStack.di[] = TR[]; DStack.cmd[] = push;
      ELSE
         DStack.cmd[] = pop;
         TR[] = DStack.do[] - 1; WR = GND; TR[].ena = VCC;
      END IF;
      IF (TR[] == 0) and !XR THEN
         RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
        ELSE
         RCMD[] = RCMD[];
      END IF;
   WHEN 15 =>
      RCMD[] = (B"0000",RCMD[WIDTH-1..4]);
END CASE;


картинка с симуляцией работы этой команды (и некоторых других):

Изображение

подпрограмма пересылки блока выглядит так:

Код:
CALL move

move:  LIT (адрес1) >R LIT (num) JNZ-MOVE-R>-RET (адрес2)

адрес1 заталкивается в стек возвратов,
на вершину стека данных ложится количество пересылок,
делается "переход" по адресу, "откуда брать данные" с отложенными командами снятия со стека возвратов адреса-приемника и возвратом в вызывающую программу

num слов пересылаются с адреса2 на адрес1

цикл пересылки состоит из двух тактов:

1. TR -> DStack, mem(PC) -> TR, PC+1 -> RStack, RStack -> PC,
2. TR -> mem(PC), PC+1 -> RStack, RStack -> PC, DStack-1 -> TR

В первом такте проверяется условие TR==0, если оно выполняется, регистр команд сдвигается на 4 бита и выполняются следующие команды.
Иначе, регистр команд сохраняется, и происходит продолжение выполнения пересылки.
Таким образом цикл пересылки крутится до тех пор, пока число на стеке данных не обнулится.
Кроме того, в начале происходит проверка - если длина пересылаемого блока равна нулю, то ничего не делается.

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


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

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


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

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


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

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