143 lines
4.7 KiB
TypeScript
143 lines
4.7 KiB
TypeScript
// Clock generation component for the LogicSimulator used on the 8-bit-computer
|
|
// Copyright (C) 2022 Sascha Nitsch
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
function EightBitClockInit() {
|
|
interface EightBitClockText {
|
|
auto: string;
|
|
manual: string;
|
|
}
|
|
|
|
interface EightBitClockParam extends BaseComponentParam {
|
|
speed?: string;
|
|
mode?: string;
|
|
auto?: string;
|
|
manual?: string;
|
|
}
|
|
class EightBitClock extends LogicBase {
|
|
private clockState: boolean;
|
|
private speed: number;
|
|
private input: string;
|
|
private runAuto: boolean;
|
|
private texts: EightBitClockText;
|
|
private manual: NodeListOf<Element> | undefined;
|
|
private speedInput: HTMLInputElement | null = null;
|
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
private timer: any = undefined;
|
|
private auto: NodeListOf<Element> | undefined;
|
|
private CLK = false;
|
|
constructor(simulator: Simulator, id: string, param: EightBitClockParam) {
|
|
super(simulator, id, param);
|
|
this.pins.set('CLK', new TriState(this, 30, -20));
|
|
this.pins.set('invCLK', new TriState(this, 30, 20));
|
|
this.clockState = false;
|
|
if (param.speed) {
|
|
this.speed = 0;
|
|
this.input = param.speed;
|
|
} else {
|
|
this.speed = 1;
|
|
this.input = 'undefined';
|
|
}
|
|
this.runAuto = param.mode ? param.mode === 'auto' : false;
|
|
this.texts = {
|
|
auto: param.auto ? param.auto : 'auto',
|
|
manual: param.manual ? param.manual : 'manual',
|
|
};
|
|
this.auto = undefined;
|
|
this.manual = undefined;
|
|
}
|
|
tick(): void {
|
|
this.clockState = !this.clockState;
|
|
if (this.manual) {
|
|
this.manual[0].textContent = this.clockState ? '1' : '0';
|
|
}
|
|
this.simulator.tick();
|
|
}
|
|
setup(canvas: SVGElement) {
|
|
super.doSetup('eightbitclock', canvas);
|
|
if (this.speed === 0) {
|
|
this.speedInput = <HTMLInputElement | null>document.getElementById(this.input);
|
|
if (this.speedInput) {
|
|
this.speedInput.addEventListener('change', this.changeSpeed.bind(this));
|
|
this.speed = parseFloat(this.speedInput.value);
|
|
if (this.runAuto) {
|
|
this.timer = setInterval(this.tick.bind(this), 500 / this.speed);
|
|
}
|
|
}
|
|
} else {
|
|
this.timer = setInterval(this.tick.bind(this), 500 / this.speed);
|
|
}
|
|
if (this.element) {
|
|
const gAuto = this.element.querySelectorAll('g.auto')[0];
|
|
this.auto = gAuto.querySelectorAll('text.inner');
|
|
gAuto.querySelectorAll('.label')[0].innerHTML = this.texts.auto;
|
|
gAuto.addEventListener('mousedown', this.toggleAuto.bind(this));
|
|
|
|
const gManual = this.element.querySelectorAll('g.manual')[0];
|
|
this.manual = gManual.querySelectorAll('text.inner');
|
|
gManual.querySelectorAll('.label')[0].innerHTML = this.texts.manual;
|
|
gManual.addEventListener('mousedown', this.toggleManual.bind(this));
|
|
}
|
|
}
|
|
|
|
update() {
|
|
const oldstate = this.CLK;
|
|
this.CLK = this.clockState;
|
|
this.getPin('CLK').setBool(this.clockState);
|
|
this.getPin('invCLK').setBool(!this.clockState);
|
|
return oldstate !== this.clockState;
|
|
}
|
|
|
|
changeSpeed() {
|
|
if (this.speedInput) {
|
|
this.speed = parseFloat(this.speedInput.value);
|
|
}
|
|
if (this.runAuto) {
|
|
clearInterval(this.timer);
|
|
this.timer = setInterval(this.tick.bind(this), 500 / this.speed);
|
|
}
|
|
}
|
|
|
|
close() {
|
|
clearInterval(this.timer);
|
|
}
|
|
|
|
toggleAuto(e: Event) {
|
|
e.preventDefault();
|
|
if (this.runAuto) {
|
|
clearInterval(this.timer);
|
|
} else {
|
|
this.timer = setInterval(this.tick.bind(this), 500 / this.speed);
|
|
}
|
|
this.runAuto = !this.runAuto;
|
|
if (this.auto) {
|
|
this.auto[0].textContent = this.runAuto ? '1' : '0';
|
|
}
|
|
}
|
|
|
|
toggleManual(e: Event) {
|
|
e.preventDefault();
|
|
this.tick();
|
|
}
|
|
}
|
|
window.EightBitClock = EightBitClock;
|
|
}
|
|
|
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
function EightBitClockDepends() {
|
|
return 'LogicBase';
|
|
}
|