Мои планы следующие - я разрабатываю универсальный API эмуляции и в процессе этой разработки выяснилось, что необходимо разработать базовый универсальный API, который позволял бы экземпляру объекта-клиента подключаться к экземпляру объекта-сервера, задействуя (только в момент начального подключения) прокси-интерфейс, необходимый для согласования различных версий универсального API, возможно использовавшихся при компиляции модулей эмуляции, экспортирующих связываемые объект-клиент и объект-сервер.
Если сказать то же самое более простым языком - добавление (при развитии API ) новых методов в таблицу виртуальных функций делает невозможной прямую динамическую компоновку порождённых в эмуляторе экземпляров объектов, созданных разработчиками с использованием библиотек API разных версий. Использование прокси-интерфейса, осуществляющего динамическую компоновку экземпляров объектов модулей эмуляции не по номеру позиции метода в таблице виртуальных функций API, а по его сигнатуре - cделает универсальный API подлинно универсальным.
Сейчас все работы по этой тематике у меня отложены ( предположительно до осени ). После завершения разработки первой версии универсального API - я выложу различные исходники, включая почти референсную модель процессора 1801ВМ1 (исследование растактовок которого, начатое Вами - ещё не закончено ).
Пока же - вот предварительный комментарий к выложенному исходнику ( если дополнительно нужен комментарий кода - то насколько подробный ? ).
Эмуляция в данном случае осуществляется покомандно. Движок эмулятора вызывает у модуля эмуляции процессора метод Steps(nSteps), передавая в качестве аргумента количество команд, которые нужно сэмулировать, и получая в глобальной переменной dwCurrentStepsLatencyNS - общее время в "эмуляторных" наносекундах, которое бы затратил реальный процессор на выполнение сэмулированных команд, которое движок затем прибавляет к общему "накопителю" qwCPU_TotalRunTimeNS, а dwCurrentStepsLatencyNS обнуляет.
Когда процессор обращается к адресу на странце ввода-вывода - происходит вызов метода Make_IO(), с предварительным занесением аргументов в переменные wLast_IO_Addr и Last_IO_Mode (выглядит довольно глупо - переделаю на обычную передачу аргументов через стек).
Т.е. основная особенность данного алгоритма эмуляции таймера состоит в том, что интересующие значения рассчитываются не на каждом "тике" тактовой частоты эмулируемого процессора (т.к. эмулируются не отдельные тики, а команды целиком), а только в те моменты, когда при эмуляции выполняемых эмулируемым процессором команд эти значения запрашиваются чтением регистров таймера.
Эмулировать довольно сложное поведение таймера только в моменты обращения к регистрам оказалось довольно непросто, но зато накладные расходы на эмуляцию равны нулю.
Если запустить таймер в любом режиме записью в регистр, а затем хоть через час прочитать значение счётчика - вся эмуляция всей истории изменений состояния таймера будет за один шаг выполнена в момент чтения регистра счётчика.
Если же не читая счётчик - остановить таймер повторной записью в регистр, то хоть за целый час, хоть за целый год максимально корректной эмуляции работы таймера, предшествовашей его остановке - программа эмуляции вообще не использует ни такта времени центрального процессора хост-машины.





Ответить с цитированием
Размещение рекламы на форуме способствует его дальнейшему развитию 
