- USB CDC 경로 복원: #define Serial Serial1 우회 제거 - rp2040js/avr8js/codemirror/xterm/monaco-editor vendor화 - /vendor 정적 라우팅 추가 (Express 5 catch-all 우회) - 부팅 완료 타임아웃 감지 (Serial 출력 없어도 8초 후 RAF 전환) - 리셋 시 Simulator 재생성으로 주변 장치 상태 초기화 - 시리얼 패널의 내부 메시지를 console.log로 이동
127 lines
4.6 KiB
JavaScript
127 lines
4.6 KiB
JavaScript
import { Timer32, Timer32PeriodicAlarm, TimerMode } from '../utils/timer32.js';
|
|
import { BasePeripheral } from './peripheral.js';
|
|
const CTRL = 0x00; // Control register
|
|
const LOAD = 0x04; // Load the watchdog timer.
|
|
const REASON = 0x08; // Logs the reason for the last reset.
|
|
const SCRATCH0 = 0x0c; // Scratch register
|
|
const SCRATCH1 = 0x10; // Scratch register
|
|
const SCRATCH2 = 0x14; // Scratch register
|
|
const SCRATCH3 = 0x18; // Scratch register
|
|
const SCRATCH4 = 0x1c; // Scratch register
|
|
const SCRATCH5 = 0x20; // Scratch register
|
|
const SCRATCH6 = 0x24; // Scratch register
|
|
const SCRATCH7 = 0x28; // Scratch register
|
|
const TICK = 0x2c; // Controls the tick generator
|
|
// CTRL bits:
|
|
const TRIGGER = 1 << 31;
|
|
const ENABLE = 1 << 30;
|
|
const PAUSE_DBG1 = 1 << 26;
|
|
const PAUSE_DBG0 = 1 << 25;
|
|
const PAUSE_JTAG = 1 << 24;
|
|
const TIME_MASK = 0xffffff;
|
|
const TIME_SHIFT = 0;
|
|
// LOAD bits
|
|
const LOAD_MASK = 0xffffff;
|
|
const LOAD_SHIFT = 0;
|
|
// REASON bits:
|
|
const FORCE = 1 << 1;
|
|
const TIMER = 1 << 0;
|
|
// TICK bits:
|
|
const COUNT_MASK = 0x1ff;
|
|
const COUNT_SHIFT = 11;
|
|
const RUNNING = 1 << 10;
|
|
const TICK_ENABLE = 1 << 9;
|
|
const CYCLES_MASK = 0x1ff;
|
|
const CYCLES_SHIFT = 0;
|
|
const TICK_FREQUENCY = 2000000; // Actually 1 MHz, but due to errata RP2040-E1, the timer is decremented twice per tick
|
|
export class RPWatchdog extends BasePeripheral {
|
|
// User provided
|
|
constructor(rp2040, name) {
|
|
super(rp2040, name);
|
|
this.scratchData = new Uint32Array(8);
|
|
this.enable = false;
|
|
this.tickEnable = true;
|
|
this.reason = 0;
|
|
this.pauseDbg0 = true;
|
|
this.pauseDbg1 = true;
|
|
this.pauseJtag = true;
|
|
/** Called when the watchdog triggers - override with your own soft reset implementation */
|
|
this.onWatchdogTrigger = () => {
|
|
this.rp2040.logger.warn(this.name, 'Watchdog triggered, but no reset handler provided');
|
|
};
|
|
this.timer = new Timer32(rp2040.clock, TICK_FREQUENCY);
|
|
this.timer.mode = TimerMode.Decrement;
|
|
this.timer.enable = false;
|
|
this.alarm = new Timer32PeriodicAlarm(this.timer, () => {
|
|
var _a;
|
|
this.reason = TIMER;
|
|
(_a = this.onWatchdogTrigger) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
});
|
|
this.alarm.target = 0;
|
|
this.alarm.enable = false;
|
|
}
|
|
readUint32(offset) {
|
|
switch (offset) {
|
|
case CTRL:
|
|
return ((this.timer.enable ? ENABLE : 0) |
|
|
(this.pauseDbg0 ? PAUSE_DBG0 : 0) |
|
|
(this.pauseDbg1 ? PAUSE_DBG1 : 0) |
|
|
(this.pauseJtag ? PAUSE_JTAG : 0) |
|
|
((this.timer.counter & TIME_MASK) << TIME_SHIFT));
|
|
case REASON:
|
|
return this.reason;
|
|
case SCRATCH0:
|
|
case SCRATCH1:
|
|
case SCRATCH2:
|
|
case SCRATCH3:
|
|
case SCRATCH4:
|
|
case SCRATCH5:
|
|
case SCRATCH6:
|
|
case SCRATCH7:
|
|
return this.scratchData[(offset - SCRATCH0) >> 2];
|
|
case TICK:
|
|
// TODO COUNT bits
|
|
return this.tickEnable ? RUNNING | TICK_ENABLE : 0;
|
|
}
|
|
return super.readUint32(offset);
|
|
}
|
|
writeUint32(offset, value) {
|
|
var _a;
|
|
switch (offset) {
|
|
case CTRL:
|
|
if (value & TRIGGER) {
|
|
this.reason = FORCE;
|
|
(_a = this.onWatchdogTrigger) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
}
|
|
this.enable = !!(value & ENABLE);
|
|
this.timer.enable = this.enable && this.tickEnable;
|
|
this.alarm.enable = this.enable && this.tickEnable;
|
|
this.pauseDbg0 = !!(value & PAUSE_DBG0);
|
|
this.pauseDbg1 = !!(value & PAUSE_DBG1);
|
|
this.pauseJtag = !!(value & PAUSE_JTAG);
|
|
break;
|
|
case LOAD:
|
|
this.timer.set((value >>> LOAD_SHIFT) & LOAD_MASK);
|
|
break;
|
|
case SCRATCH0:
|
|
case SCRATCH1:
|
|
case SCRATCH2:
|
|
case SCRATCH3:
|
|
case SCRATCH4:
|
|
case SCRATCH5:
|
|
case SCRATCH6:
|
|
case SCRATCH7:
|
|
this.scratchData[(offset - SCRATCH0) >> 2] = value;
|
|
break;
|
|
case TICK:
|
|
this.tickEnable = !!(value & TICK_ENABLE);
|
|
this.timer.enable = this.enable && this.tickEnable;
|
|
this.alarm.enable = this.enable && this.tickEnable;
|
|
// TODO - handle CYCLES (tick also affectes timer)
|
|
break;
|
|
default:
|
|
super.writeUint32(offset, value);
|
|
}
|
|
}
|
|
}
|