Которую я недавно написал на Java и C++, только в упрощённом варианте.
Вот схема:
I
+---+ clock
----| |o--*---
| +---+ |
| |
*------------
|
--- R
| |
| |
---
|
---
-
.Она состоит из двух элементов: резистора R, подключённого к земле (оттягивает линию вниз, если она никуда не подключена) и инвертора I, который берёт свой собственный выхлоп и инвертирует.
Всё вместе образует тактовый генератор. Полупериод генератора определяется задержкой на инверторе.
Уровень на линии clock определяется так называемой функцией разрешения (resolution function). Она пробегает по всем подключённым к линии проводам, смотрит на их состояние и выдаёт суммарное состояние.
В нашем случае состояний будет три: 0, 1 и Z (третье, когда линия "подвешена" и никуда не подключена, это исходное состояние).
Таблица, соответственно, такая:
| 0 | 1 | Z
-------------
0| 0 | 1 | 0
1| 1 | 1 | 1
Z| 0 | 1 | Z1 подтягивает кверху все остальные состояния.
Если всё переводить в однотипные элементы, то схема изменится:
RF
+---+ I
0 --| | +---+ clock
| |---| |o--*---
--| | +---+ |
| +---+ |
| |
-------------------RF - функция разрешения. Её задержку можно считать равной 0. Один из её входов подтянут к 1, второй поступает извне, с выхода инвертора.
Я смоделировал работу этой схемы.
Как она работает.
На старте все линии находятся в состоянии Z. В самом начале работы константа переводит свой выход в 0, это происходит в момент времени 0. Далее начинает реагировать RF - на входе у неё пара (0,Z), значит на выход надо подать 0. Тут включается инвертор, он видит, что на входе 0 вместо Z, значит на выход надо подать 1, указав, что изменение произойдёт после задержки. На вход RF придёт пара (0,1), она переключится в 1, инвертор переключится в 0 и начнётся процесс генерации.
Конструирование схемы вот:
Manager mgr = new SimManager( );
long invDelay = 100;
/* create components */
Component highDriver = new Constant(mgr, 0, SimValue.ZERO);
Component resolve = new ResolveStd(mgr, 1);
Component invertor = new GateNot(mgr, invDelay, 2);
/* set names */
highDriver.setName("highDriver");
resolve.setName("resolve");
invertor.setName("invertor");
/* create connections. */
highDriver.drives(0,resolve,0); /* highDriver output 0 drives resolve input 0 */
invertor.drives(0,resolve,1);
resolve.drives(0,invertor,0);
/* force initial events */
highDriver.start(mgr); /* highDriver should force resolve input to become high */
invertor.start(mgr);
resolve.start(mgr);
Можно запускать mgr.loop(endTime) для симуляции.
Выходы-входы соединяются по номерам, поскольку о внутренностях объектов никто ничего знать не должен. И вообще, это всё будет загружаться извне, возможно, как-то преобразовываться и тп. Поэтому обработка должна быть как можно более общей.
На этой схеме я тренировал симуляцию схем общего вида.
Хороший стартовый пример, есть всё, что нужно, и постоянно двигается. За один цикл генератора происходит четыре посылки сообщения: инвертор шлёт значение функции разрешения, функция разрешения инвертору и так ещё один раз. Одна итерация - это полупериод, две посылки.
Так что если кому интересно сравнить быстродействие, может написать любое количество вариантов на любом ЯП. ;)
У меня получилось то, что получилось - C++ на gcc-3.4 отстаёт от Java6 процентов на 6-10. При применении -fomit-frame-pointer он идёт голова-в-голову (<3%). Но в общем и целом, писать такие задачи на C++ смысла нет.
PS
А я всё-таки придумал, похоже, как это можно ещё ускорить. Но потом. ;)
PPS
Если у инвертора количество входов и выходов фиксировано, то у функции разрешения количество входов произвольно. А могут встретиться и элементы с произвольным количеством входов и выходов.
PPPS
Здесь всё максимально упрощено. ;)