Comments 15
Но как сделать быстрый мастер – мы уже знаем.
А какой мастер вы имеете ввиду?
Ну, и перекачка данных через JTAG будет идти медленнее, чем через FT245. Но опять же, мы уже знаем, как перекачивать всё через FT245.
Не очень понятно, а почему вы здесь сравниваете FT245 и JTAG?
А какой мастер вы имеете ввиду?Мастер из процессорного ядра Nios II. Он был впервые применён ещё в самой первой статье цикла и дальше кочует из статьи в статью.
Не очень понятно, а почему вы здесь сравниваете FT245 и JTAG?Протокол FT245-SYNC заложен, как штатный для сязи ПЛИС с центральным процессором Redd (реализован на чипе FT2232H). Работа с ним была рассмотрена ранее, тогда же сделаны замеры его скорости. Первое рассмотрение — во второй части тут, далее — тут.
Но как было видно в статьях по ссылкам, данная функциональность несколько сложна в добавлении. Зато скоростная. Если же скорость обмена не критична (например, данных не очень много) — можно воспользоваться работой через JTAG канал, описанный в этой статье. Выигрываем в скорости разработки и в свободной памяти ПЛИС, проигрываем в скорости работы.
А дальше — каждый решает, что ему важнее в данный конкретный момент. Владея обоими методами, можно оптимизировать работу под каждый конкретный случай.
Что через JTAG можно в память напрямую писать что через FT245-SYNC.
JTAG канал встроен в ПЛИС от её рождения. Описанная тут функциональность — встроена в среду разработки. Как видно, в рамках данной статьи мы не написали ни одной строчки своего кода ни для ПЛИС, ни для ЭВМ. Нам хватило всего встроенного.
FT245-SYNC добавлен в комплекс Redd потому, что мы его выбрали. Мы заложили в схему этого комплекса чип FT2232H. Поэтому чтобы его поддерживать, в статьях, на которые я дал ссылки выше, я сначала проектирую автомат, затем — делаю его реализацию на языке Verilog, затем — оборачиваю его в компонент, затем — вставляю в систему, затем — добавляю немного штатной обвязки, затем — связываю всё это. И в итоге — у меня получается FIFO, к которому имеет доступ только программа для процессора NIOS II. Но так же я могу написать мастера, имеющего доступ к Memory Mapped шине. Но лично я — не буду этого делать. Сил много потрачу. Проще ограничиться FIFO и брать оттуда данные программно, либо программно же класть их туда.
Как видите, технически всё возможно, но реально всё похоже на анекдот:
— Доктор, я после операции буду играть на скрипке?
— Конечно будете!
— Спасибо, доктор, а то я раньше не умел.
Вот если приложить массу усилий, то FT245-SYNC к шине AVALON-MM приладить можно (надо долго учиться играть на скрипке). Зато всё будет идеально. Описанную же в этой статье функциональность сделала для нас «мать-природа» в лице инженеров Альтеры. Но она — смешная по производительности. Зато не надо мучиться.
То есть, технически — всё заменяемо. Но трудозатраты — не сопоставимы. Поэтому я не скажу, что всё взаимо заменяемо. Хотя бы потому, что одна из функций — врождённая в систему, а вторая — нет.
как сделать идеальную программу, перехватывающую оба потока, я пока не знаю. Если кто-то приведёт в комментариях готовые решения, я буду благодарен. В первую очередь – под Debian, чтобы не гонять большие потоки данных по сети.
#include <stdlib.h>
#include <unistd.h>
#define BUFFER_SIZE (4096)
int main(int argc, char **argv) {
int pipes_in[2] = {-1};
int pipes_out[2] = {-1};
if (pipe(pipes_in) != 0) {
perror("Can't create input pipes pair!");
exit(EXIT_FAILURE);
}
if (pipe(pipes_out) != 0) {
perror("Can't create output pipes pair!");
exit(EXIT_FAILURE);
}
int fork_result = fork();
if (fork_result == 0) {
close(pipes_in[1]); // Close unused write end
close(pipes_out[0]); // Close unused read end
dup2(pipes_in[0], 0); // Change stdin to a pipe
dup2(pipes_out[1], 1); // Change stdout to a pipe
close(pipes_in[0]); // Cleanup opened FDs
close(pipes_out[1]); // Cleanup opened FDs
// Start slave binary
execlp("cat", "cat"); // To communicate with local process
// execlp("nc", "nc", "127.0.0.1", "1234"); // To communicate over network (to 127.0.0.1:1234)
} else if (fork_result < 0) {
perror("Fork failed!");
exit(EXIT_FAILURE);
}
// Master process goes here
close(pipes_in[0]); // Close unused read end
close(pipes_out[1]); // Close unused write end
// Open pipe end as FILE* for fgets()/fputs()
FILE *pipe_from_slave = fdopen(pipes_out[0], "r");
if (pipe_from_slave == NULL) {
perror("Can't reopen pipe from slave as FILE*");
exit(EXIT_FAILURE);
}
FILE *pipe_to_slave = fdopen(pipes_in[1], "w");
if (pipe_to_slave == NULL) {
perror("Can't reopen pipe to slave as FILE*");
exit(EXIT_FAILURE);
}
char buffer[BUFFER_SIZE];
while (fgets(buffer, BUFFER_SIZE, stdin)) {
printf("Master: Got line from console: %s", buffer);
fprintf(pipe_to_slave, "%s", buffer);
fflush(pipe_to_slave);
printf("Master: Wrote line to slave: %s", buffer);
if (fgets(buffer, BUFFER_SIZE, pipe_from_slave) != NULL) {
printf("Master: Got line from slave: %s", buffer);
} else {
perror("Failed to read from slave");
exit(EXIT_FAILURE);
}
}
exit(EXIT_SUCCESS);
}
Спасибо! Буду пробовать!
Основной смысл задачи — создать два пайпа (первый на передачу master -> slave, второй на передачу slave -> master), форкнуться и сразу же позакрывать в обоих форках неиспользуемые стороны пайпов (у master'а — read end у первого пайпа и write end у второго, у slave'а — наоборот).
Затем у slave'а надо превратить соответствующие концы пайпов (оставшиеся открытыми) в stdin и stdout вызовами dup2 (read end первого пайпа должен стать stdin, write end второго пайпа — stdout) и оригинальные дескрипторы тоже закрыть (чтобы не маячили), после чего запустить вызовом exec** уже реальный slave-процесс, который унаследует stdin и stdout как пайпы от и к master'у.
А master тем временем уже может читать из read end второго пайпа и писать во write end первого пайпа.
Я так понимаю, это только на Unix системах работает?
Но в рамках цикла статей важнее Linux (Debian) вариант. Потому что система запускается на ПЛИС, физически подключённой к ЭВМ с Линуксом. Значит, управляющий код на той ЭВМ и должен исполняться. Так будет производительнее всего.
Еще желательно кросплатформенно, на сколько это возможно
Или сделать библиотеку с универсальным интерфейсом. Собрать версии библиотеки под каждую ОС и подключать их к проектам. А пользователи, опять же, не будут знать, к кому обращаются. Главное — чтобы интерфейс был универсальным.
Но это — уже выходит за рамки как статьи, так и цикла.
Использование процессорной системы Nios II без процессорного ядра Nios II