Files
homeclaw/web-ui/vendor/rp2040js/peripherals/ppb.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

226 lines
8.5 KiB
JavaScript

import { MAX_HARDWARE_IRQ } from '../irq.js';
import { Timer32, Timer32PeriodicAlarm, TimerMode } from '../utils/timer32.js';
import { BasePeripheral } from './peripheral.js';
export const CPUID = 0xd00;
export const ICSR = 0xd04;
export const VTOR = 0xd08;
export const SHPR2 = 0xd1c;
export const SHPR3 = 0xd20;
const SYST_CSR = 0x010; // SysTick Control and Status Register
const SYST_RVR = 0x014; // SysTick Reload Value Register
const SYST_CVR = 0x018; // SysTick Current Value Register
const SYST_CALIB = 0x01c; // SysTick Calibration Value Register
const NVIC_ISER = 0x100; // Interrupt Set-Enable Register
const NVIC_ICER = 0x180; // Interrupt Clear-Enable Register
const NVIC_ISPR = 0x200; // Interrupt Set-Pending Register
const NVIC_ICPR = 0x280; // Interrupt Clear-Pending Register
// Interrupt priority registers:
const NVIC_IPR0 = 0x400;
const NVIC_IPR1 = 0x404;
const NVIC_IPR2 = 0x408;
const NVIC_IPR3 = 0x40c;
const NVIC_IPR4 = 0x410;
const NVIC_IPR5 = 0x414;
const NVIC_IPR6 = 0x418;
const NVIC_IPR7 = 0x41c;
/** ICSR Bits */
const NMIPENDSET = 1 << 31;
const PENDSVSET = 1 << 28;
const PENDSVCLR = 1 << 27;
const PENDSTSET = 1 << 26;
const PENDSTCLR = 1 << 25;
const ISRPREEMPT = 1 << 23;
const ISRPENDING = 1 << 22;
const VECTPENDING_MASK = 0x1ff;
const VECTPENDING_SHIFT = 12;
const VECTACTIVE_MASK = 0x1ff;
const VECTACTIVE_SHIFT = 0;
/** PPB stands for Private Periphral Bus.
* These are peripherals that are part of the ARM Cortex Core, and there's one copy for each processor core.
*
* Included peripheral: NVIC, SysTick timer
*/
export class RPPPB extends BasePeripheral {
constructor(rp2040, name) {
super(rp2040, name);
// Systick
this.systickCountFlag = false;
this.systickClkSource = false;
this.systickIntEnable = false;
this.systickReload = 0;
this.systickTimer = new Timer32(this.rp2040.clock, this.rp2040.clkSys);
this.systickAlarm = new Timer32PeriodicAlarm(this.systickTimer, () => {
this.systickCountFlag = true;
if (this.systickIntEnable) {
this.rp2040.core.pendingSystick = true;
this.rp2040.core.interruptsUpdated = true;
}
this.systickTimer.set(this.systickReload);
});
this.systickTimer.top = 0xffffff;
this.systickTimer.mode = TimerMode.Decrement;
this.systickAlarm.target = 0;
this.systickAlarm.enable = true;
this.reset();
}
reset() {
this.writeUint32(SYST_CSR, 0);
this.writeUint32(SYST_RVR, 0xffffff);
this.systickTimer.set(0xffffff);
}
readUint32(offset) {
const { rp2040 } = this;
const { core } = rp2040;
switch (offset) {
case CPUID:
return 0x410cc601; /* Verified against actual hardware */
case ICSR: {
const pendingInterrupts = core.pendingInterrupts || core.pendingPendSV || core.pendingSystick || core.pendingSVCall;
const vectPending = core.vectPending;
return ((core.pendingNMI ? NMIPENDSET : 0) |
(core.pendingPendSV ? PENDSVSET : 0) |
(core.pendingSystick ? PENDSTSET : 0) |
(pendingInterrupts ? ISRPENDING : 0) |
(vectPending << VECTPENDING_SHIFT) |
((core.IPSR & VECTACTIVE_MASK) << VECTACTIVE_SHIFT));
}
case VTOR:
return core.VTOR;
/* NVIC */
case NVIC_ISPR:
return core.pendingInterrupts >>> 0;
case NVIC_ICPR:
return core.pendingInterrupts >>> 0;
case NVIC_ISER:
return core.enabledInterrupts >>> 0;
case NVIC_ICER:
return core.enabledInterrupts >>> 0;
case NVIC_IPR0:
case NVIC_IPR1:
case NVIC_IPR2:
case NVIC_IPR3:
case NVIC_IPR4:
case NVIC_IPR5:
case NVIC_IPR6:
case NVIC_IPR7: {
const regIndex = (offset - NVIC_IPR0) >> 2;
let result = 0;
for (let byteIndex = 0; byteIndex < 4; byteIndex++) {
const interruptNumber = regIndex * 4 + byteIndex;
for (let priority = 0; priority < core.interruptPriorities.length; priority++) {
if (core.interruptPriorities[priority] & (1 << interruptNumber)) {
result |= priority << (8 * byteIndex + 6);
}
}
}
return result;
}
case SHPR2:
return core.SHPR2;
case SHPR3:
return core.SHPR3;
/* SysTick */
case SYST_CSR: {
const countFlagValue = this.systickCountFlag ? 1 << 16 : 0;
const clkSourceValue = this.systickClkSource ? 1 << 2 : 0;
const tickIntValue = this.systickIntEnable ? 1 << 1 : 0;
const enableFlagValue = this.systickTimer.enable ? 1 << 0 : 0;
this.systickCountFlag = false;
return countFlagValue | clkSourceValue | tickIntValue | enableFlagValue;
}
case SYST_CVR:
return this.systickTimer.counter;
case SYST_RVR:
return this.systickReload;
case SYST_CALIB:
return 0x0000270f;
}
return super.readUint32(offset);
}
writeUint32(offset, value) {
const { rp2040 } = this;
const { core } = rp2040;
const hardwareInterruptMask = (1 << MAX_HARDWARE_IRQ) - 1;
switch (offset) {
case ICSR:
if (value & NMIPENDSET) {
core.pendingNMI = true;
core.interruptsUpdated = true;
}
if (value & PENDSVSET) {
core.pendingPendSV = true;
core.interruptsUpdated = true;
}
if (value & PENDSVCLR) {
core.pendingPendSV = false;
}
if (value & PENDSTSET) {
core.pendingSystick = true;
core.interruptsUpdated = true;
}
if (value & PENDSTCLR) {
core.pendingSystick = false;
}
return;
case VTOR:
core.VTOR = value;
return;
/* NVIC */
case NVIC_ISPR:
core.pendingInterrupts |= value;
core.interruptsUpdated = true;
return;
case NVIC_ICPR:
core.pendingInterrupts &= ~value | hardwareInterruptMask;
return;
case NVIC_ISER:
core.enabledInterrupts |= value;
core.interruptsUpdated = true;
return;
case NVIC_ICER:
core.enabledInterrupts &= ~value;
return;
case NVIC_IPR0:
case NVIC_IPR1:
case NVIC_IPR2:
case NVIC_IPR3:
case NVIC_IPR4:
case NVIC_IPR5:
case NVIC_IPR6:
case NVIC_IPR7: {
const regIndex = (offset - NVIC_IPR0) >> 2;
for (let byteIndex = 0; byteIndex < 4; byteIndex++) {
const interruptNumber = regIndex * 4 + byteIndex;
const newPriority = (value >> (8 * byteIndex + 6)) & 0x3;
for (let priority = 0; priority < core.interruptPriorities.length; priority++) {
core.interruptPriorities[priority] &= ~(1 << interruptNumber);
}
core.interruptPriorities[newPriority] |= 1 << interruptNumber;
}
core.interruptsUpdated = true;
return;
}
case SHPR2:
core.SHPR2 = value;
return;
case SHPR3:
core.SHPR3 = value;
return;
// SysTick
case SYST_CSR:
this.systickClkSource = value & (1 << 2) ? true : false;
this.systickIntEnable = value & (1 << 1) ? true : false;
this.systickTimer.enable = value & (1 << 0) ? true : false;
return;
case SYST_CVR:
this.systickTimer.set(0);
return;
case SYST_RVR:
this.systickReload = value;
return;
default:
super.writeUint32(offset, value);
}
}
}