[bETA]mENЦитата:
Wind писал:
Это прерывание происходит 50.94 раз в секунду для NTSC (для 50 PAL). Для Sega Dreamcast это должно происходить 200000000/50.94 т.е
if (sh4.cycle >= 3333333) Vsync();
50.94??? А может все-таки 59.94
WindМожет быть, очень может быть, одним словм не то написал
Organic Точного понятия "времени" в эмуляторах не существует. Вся причина в том, что на реальном процессоре выполнение одной инструкции занимает ровно N тактов реального-же времени. Я намеренно не буду говорить про суперскалярную архитектуру и всякую кэш память - естественно они влияют на время исполнения инструкции, но это всего лишь оптимизирующий фактор для уменьшения времени исполнения, и им можно пренебречь, т.е. если из процессора вырезать эти аппаратные узлы, с точки зрения программы он хуже работать не будет, а только медленней.
На практике понятие "время" удобней делить на два понятия : реальное время и программное время. Реальное время - это то время, которое показвает компьютер, то есть реальное местное время. Программное время - это время, которое показывает некий программный счетчик. К примеру, как писал Wind - счетчик инструкций.
Так вот - в эмуляторе реальное время НЕ СОВПАДАЕТ с програмным. Т.е. эмулятор никокгда не выполнит ровно столько-же инструкций, за одну *реальную* секунду, сколько их выполнит реальный процессор. Это сделать невозможно.
Плохо это, или хорошо? На самом деле эмулятору на это наплевать. Ведь если посудить, то за *равные* промежутки реального и программного времени, в эмуляторе выполнится столько-же инструкций, и возникнет столько-же прерываний, сколько и на реальном процессоре. Соблюдение этого правила и является основной задачей *правильной* эмуляции тайминга.
И действительно, если эмулятор за одну реальную секунду, выполнит больше действий, чем реальная система - мы его "притормозим" - нам это не сложно. Если эмулятор будет работать медленней - мы получим меньше FPS, и будем искать пути для его увеличения.
Несколько советов :
- При написании эмулятора важно четко понимать - с каким "временем" ты имеешь дело!
- При эмуляции DMA чаще всего можно проигнорировать факт параллельной записи в память процессора и DMA-контроллера. Т.е. для DMA можно пренебречь точным таймингом.
- Нужно строго следить, чтобы выполнялось основное правило эмуляции тайминга. Т.е. если на реальной системе происходит 60 кадровых прерываний за одну реальную секунду, то и в эмуляторе должно происходить 60 прерываний, за одну программную секунду. Если будет "недосдача" или "перебор", то эмулируемой программе это может очень не понравиться
- Удобно завести константу - ONE_SECOND, которая будет показывать значение программного счетчика, соответствующего одной программной секунде.
- Не пытайтесь эмулировать таймеры реальным временем. Хлопот не оберетесь.
0 error(s), 0 warning(s)
RomikBНе знаю насколько я нарушил советы Органика...
У меня используеться смесь реального времени с програмным. Вначале задаеться длина програмной секунды, по умолчанию = секунда реальная. И 60 раз за эту секунду(реально-програмную) вызываеться програмный обрабочик VSync. Т.е. все програмные таймеры привязываються (через коэффициент) именно к реальному времени.
Насколько это правильно сказать не могу, так как тестировал только на демках, на которых всё прекрасно работает. Но ничего проще и удобней для использования вместе с динамическим рекомпилятором в котором нету никакого подсчета инструкций я не нашел.
WindOrganic красиво расписал надо было мне всю статейку в таком духе расписать. Такой абстрактный подход весьама удобен для понимания. Мне прсто хотелось привести конретный пример. Кстати может ответищь на вопрос заданый в топике по GQ насчет "динарека"
RomikB я не понял ты нашел какие-то сложности подсчета инструкций при использовании динамической рекомпиляции? Для меня наооборот проще подсчитать такты эмулируемой системы не жели использовать реалные часы.
RomikBWind, приведи пример такого подсчета, чтобы он не сказывался на скорости эмуляции и на размере кода?
А считать реальные часы очень просто...
WindНу конечно такого примера я привести не смогу.
Но неужели плюс одна иструкция на каждую команду так уж существенно. А обновление таймеров производи, как я уже написал выше в конце инструкций перехода. В сочетании с динамической рекомпиляцией этот подход очень удобен: исполнили очередной блок обновли таймеры.
RomikBЦитата:
Wind писал:
Ну конечно такого примера я привести не смогу.
Но неужели плюс одна иструкция на каждую команду так уж существенно. А обновление таймеров производи, как я уже написал выше в конце инструкций перехода. В сочетании с динамической рекомпиляцией этот подход очень удобен: исполнили очередной блок обновли таймеры.
Ну одна иструкция это 5 байт и 3 такта.
inc [mem]
Если учесть что одна рекомпилированная иструкция, кроме переходов, занимает 16 байт и выполняеться за 4-10 тактов, то вполне немало...
WindЯ тебе не предлагаю вставлять счетчик тактов в "рекомпилированый код", проще увеличивать счетчик еще на стадии дисассемблирования-рекомпилирования.
Цитата:
RomikB писал:
Если учесть что одна рекомпилированная иструкция, кроме переходов, занимает 16 байт и выполняеться за 4-10 тактов, то вполне немало...
Это ты я так пониямаю говоришь о MIPS3000, вопрос в том, а какое среднее число тактов получается. Если оно стремится к 10 то, что-то слишком много. У этого процессора нет "флагового регистра", а без него эмуляция для меня лично значительно упрощается.
Кстати как у тебя с опытом эмуляции Видео?
RomikBнет я говорю уже про рекомпилированный код...
"занимает 16 байт и выполняеться за 4-10 тактов, то вполне немало..."
Эмуляция видео - никакая - никогда не занимался графикой.
OrganicМожно считать программное время отдельным потоком (thread). Тогда не нужно генерировать дополнительный код для инкремента счетчика.
0 error(s), 0 warning(s)
RomikBЦитата:
Organic писал:
Можно считать программное время отдельным потоком (thread). Тогда не нужно генерировать дополнительный код для инкремента счетчика.
В этом случае придеться потратить кучу времени и ресурсоф на синхронизацию главного потока эмуляции с потоком этого счетчика.
OrganicЦитата:
Цитата:
В этом случае придеться потратить кучу времени и ресурсоф на синхронизацию главного потока эмуляции с потоком этого счетчика
А вот я тоже думаю.. Надо-ли синхронизировать поток CPU с потоком программного времени? Так-ли это необходимо? Ведь всё, что делает поток времени - увеличивает счетчик. Тем же самым занимается поток CPU.
0 error(s), 0 warning(s)
RomikB Org, поясни как ты намерен считать програмное время в отдельном потоке, откуда данные брать будешь?