Дополнительные тесты позволили выявить несколько ошибок и неточностей в первой версии алгоритма.
Вот новая версия алгоритма, ещё более точно (как я полагаю) эмулирующая работу встроенного таймера процессора 1801ВМ1:
Код:typedef unsigned long long QWORD; typedef unsigned long DWORD; typedef unsigned short word; #define WORD(a) (*(unsigned short *)&aMemory[a]) PowerON() { WORD(0177706) = wCPU_ID; wVE_Timer_Counter = 0177777; WORD(0177710) = wVE_Timer_Counter; WORD(0177712) = 0177400; nVE_MonitoredExpiryCount = 0; bVE_Expiry = false; bVE_Go = false; } Reset() { WORD(0177712) = 0; Last_IO_Mode = IO_WRITE; wLast_IO_Addr = 0177712; Make_IO(); } Make_IO() { switch( wLast_IO_Addr ) { // VE-Timer Counter Initial Value case 0177706: { if( Last_IO_Mode == IO_WRITE ) { Last_IO_Mode = IO_READ; wLast_IO_Addr = 0177710; Make_IO(); Last_IO_Mode = IO_WRITE; wLast_IO_Addr = 0177706; if( bVE_Go && !bVE_NoReload && !bVE_NoRestart ) { QWORD qwCurrentCPU_RunTimeNS = qwCPU_TotalRunTimeNS; qwCurrentCPU_RunTimeNS += dwCurrentStepsLatencyNS; QWORD qwCurrentCPU_Clocks = qwCurrentCPU_RunTimeNS/uCPU_CycleNS; if( qwCurrentCPU_Clocks >= qwNextVE_TimerStart_CPU_Clocks ) { qwPrevVE_TimerStart_CPU_Clocks = qwNextVE_TimerStart_CPU_Clocks; dwPrevInitialVE_CounterVal = dwNextInitialVE_CounterVal; QWORD qwUsedCPU_Clocks = qwCurrentCPU_Clocks - qwPrevVE_TimerStart_CPU_Clocks; QWORD qwCurrentVE_Timer_Clocks = qwUsedCPU_Clocks/nVE_CPU_Clock_Divider; DWORD dwTimerClocksLow = qwCurrentVE_Timer_Clocks % dwPrevInitialVE_CounterVal; qwNextVE_TimerStart_CPU_Clocks = qwPrevVE_TimerStart_CPU_Clocks; qwNextVE_TimerStart_CPU_Clocks += ( dwPrevInitialVE_CounterVal - dwTimerClocksLow ) * nVE_CPU_Clock_Divider; } dwNextInitialVE_CounterVal = WORD(0177706); if( !dwNextInitialVE_CounterVal ) { dwNextInitialVE_CounterVal = 0x10000; } } } } break; // VE-Timer Counter case 0177710: { if( Last_IO_Mode == IO_WRITE ) { WORD(0177710) = wVE_Timer_Counter; } else { if( bVE_Go ) { QWORD qwCurrentCPU_RunTimeNS = qwCPU_TotalRunTimeNS; qwCurrentCPU_RunTimeNS += dwCurrentStepsLatencyNS; QWORD qwCurrentCPU_Clocks = qwCurrentCPU_RunTimeNS/uCPU_CycleNS; QWORD qwVE_TimerStart_CPU_Clocks = qwPrevVE_TimerStart_CPU_Clocks; DWORD dwInitialVE_CounterVal = dwPrevInitialVE_CounterVal; if( qwCurrentCPU_Clocks >= qwNextVE_TimerStart_CPU_Clocks ) { bVE_Expiry = true; if( !bVE_NoRestart ) { qwVE_TimerStart_CPU_Clocks = qwNextVE_TimerStart_CPU_Clocks; dwInitialVE_CounterVal = dwNextInitialVE_CounterVal; } } QWORD qwUsedCPU_Clocks = qwCurrentCPU_Clocks - qwVE_TimerStart_CPU_Clocks; QWORD qwCurrentVE_Timer_Clocks = qwUsedCPU_Clocks/nVE_CPU_Clock_Divider; DWORD dwTimerClocksHi = qwCurrentVE_Timer_Clocks / dwInitialVE_CounterVal; DWORD dwTimerClocksLow = qwCurrentVE_Timer_Clocks % dwInitialVE_CounterVal; if( bVE_Expiry ) { if( bVE_Monitor && (dwTimerClocksHi > nVE_MonitoredExpiryCount) ) { nVE_MonitoredExpiryCount = dwTimerClocksHi; } if( bVE_NoReload ) { wVE_Timer_Counter = dwInitialVE_CounterVal - dwTimerClocksLow; } else if( bVE_NoRestart ) { bVE_Go = false; wVE_Timer_Counter = WORD(0177706); if( dwTimerClocksHi == 1 && !dwTimerClocksLow ) { if( qwCurrentCPU_Clocks%128 < 5 ) { wVE_Timer_Counter = 0; } } } else { wVE_Timer_Counter = dwInitialVE_CounterVal - dwTimerClocksLow; if( !dwTimerClocksLow ) { if( qwCurrentCPU_Clocks%128 < 5 ) { wVE_Timer_Counter = 0; } } } } else { // !bVE_Expiry wVE_Timer_Counter = dwInitialVE_CounterVal - dwTimerClocksLow; } WORD(0177710) = wVE_Timer_Counter; } } } break; // VE-Timer CSR case 0177712: { IO_ModeType IO_Mode = Last_IO_Mode; Last_IO_Mode = IO_READ; wLast_IO_Addr = 0177710; Make_IO(); wLast_IO_Addr = 0177712; Last_IO_Mode = IO_Mode; word wVE_Timer_CSR = WORD(0177712); if( Last_IO_Mode == IO_READ ) { if( bVE_Expiry ) { if( bVE_Monitor && nVE_MonitoredExpiryCount > 1 ) { wVE_Timer_CSR |= BIT_7; } if( bVE_NoRestart && !bVE_NoReload ) { wVE_Timer_CSR &= ~BIT_4; } } WORD(0177712) = wVE_Timer_CSR|0xFF00; } else { // Last_IO_Mode == IO_WRITE if( nVE_MonitoredExpiryCount ) { nVE_MonitoredExpiryCount = 2; } bVE_Expiry = false; bVE_Go = wVE_Timer_CSR & BIT_4; if( wVE_Timer_CSR & BIT_0 ) { bVE_Go = false; } bVE_NoReload = wVE_Timer_CSR & BIT_1; bVE_Monitor = wVE_Timer_CSR & BIT_2; bVE_NoRestart = wVE_Timer_CSR & BIT_3; nVE_CPU_Clock_Divider = 128; if( wVE_Timer_CSR & BIT_5 ) { nVE_CPU_Clock_Divider *= 16; } if( wVE_Timer_CSR & BIT_6 ) { nVE_CPU_Clock_Divider *= 4; } if( bVE_Go ) { QWORD qwCurrentCPU_RunTimeNS = qwCPU_TotalRunTimeNS; qwCurrentCPU_RunTimeNS += dwCurrentStepsLatencyNS; QWORD qwCurrentCPU_Clocks = qwCurrentCPU_RunTimeNS/uCPU_CycleNS; QWORD qwVE_TimerStart_CPU_Clocks = qwCurrentCPU_Clocks; qwVE_TimerStart_CPU_Clocks -= qwVE_TimerStart_CPU_Clocks%128; QWORD dwInitialVE_CounterVal = WORD(0177706); if( !dwInitialVE_CounterVal ) { dwInitialVE_CounterVal = 0x10000; } dwPrevInitialVE_CounterVal = dwInitialVE_CounterVal; dwNextInitialVE_CounterVal = dwInitialVE_CounterVal; if( bVE_NoReload ) { dwNextInitialVE_CounterVal = 0x10000; } qwPrevVE_TimerStart_CPU_Clocks = qwVE_TimerStart_CPU_Clocks; qwNextVE_TimerStart_CPU_Clocks = qwVE_TimerStart_CPU_Clocks; qwNextVE_TimerStart_CPU_Clocks += dwInitialVE_CounterVal * nVE_CPU_Clock_Divider; } wVE_Timer_Counter = WORD(0177706); WORD(0177710) = wVE_Timer_Counter; WORD(0177712) = wVE_Timer_CSR|0xFF00; } } break; } }




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