Files
homeclaw/web-ui/vendor/avr8js/peripherals/clock.js
T
kim 209f3a3aef v3.0.6: RP2040 에뮬레이터 개선 — USB CDC, vendor화, 부팅 감지
- USB CDC 경로 복원: #define Serial Serial1 우회 제거
- rp2040js/avr8js/codemirror/xterm/monaco-editor vendor화
- /vendor 정적 라우팅 추가 (Express 5 catch-all 우회)
- 부팅 완료 타임아웃 감지 (Serial 출력 없어도 8초 후 RAF 전환)
- 리셋 시 Simulator 재생성으로 주변 장치 상태 초기화
- 시리얼 패널의 내부 메시지를 console.log로 이동
2026-06-19 15:49:36 +09:00

55 lines
2.0 KiB
JavaScript

// SPDX-License-Identifier: MIT
// Copyright (c) Uri Shaked and contributors
const CLKPCE = 128;
export const clockConfig = {
CLKPR: 0x61,
};
const prescalers = [
1, 2, 4, 8, 16, 32, 64, 128, 256,
// The following values are "reserved" according to the datasheet, so we measured
// with a scope to figure them out (on ATmega328p)
2, 4, 8, 16, 32, 64, 128,
];
export class AVRClock {
constructor(cpu, baseFreqHz, config = clockConfig) {
this.cpu = cpu;
this.baseFreqHz = baseFreqHz;
this.config = config;
this.clockEnabledCycles = 0;
this.prescalerValue = 1;
this.cyclesDelta = 0;
this.cpu.writeHooks[this.config.CLKPR] = (clkpr) => {
if ((!this.clockEnabledCycles || this.clockEnabledCycles < cpu.cycles) && clkpr === CLKPCE) {
this.clockEnabledCycles = this.cpu.cycles + 4;
}
else if (this.clockEnabledCycles && this.clockEnabledCycles >= cpu.cycles) {
this.clockEnabledCycles = 0;
const index = clkpr & 0xf;
const oldPrescaler = this.prescalerValue;
this.prescalerValue = prescalers[index];
this.cpu.data[this.config.CLKPR] = index;
if (oldPrescaler !== this.prescalerValue) {
this.cyclesDelta =
(cpu.cycles + this.cyclesDelta) * (oldPrescaler / this.prescalerValue) - cpu.cycles;
}
}
return true;
};
}
get frequency() {
return this.baseFreqHz / this.prescalerValue;
}
get prescaler() {
return this.prescalerValue;
}
get timeNanos() {
return ((this.cpu.cycles + this.cyclesDelta) / this.frequency) * 1e9;
}
get timeMicros() {
return ((this.cpu.cycles + this.cyclesDelta) / this.frequency) * 1e6;
}
get timeMillis() {
return ((this.cpu.cycles + this.cyclesDelta) / this.frequency) * 1e3;
}
}