148 lines
5.8 KiB
TypeScript
148 lines
5.8 KiB
TypeScript
|
// Multiple register component for the LogicSimulator used by 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/>.
|
||
|
|
||
|
interface MultiRegisterParam extends BaseComponentParam {
|
||
|
count?: number;
|
||
|
}
|
||
|
|
||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
|
function MultiRegisterInit() {
|
||
|
class MultiRegister extends LogicBase {
|
||
|
private regcount: number;
|
||
|
private r: number[];
|
||
|
private oldCLK: boolean;
|
||
|
private CLK: boolean;
|
||
|
private RON: boolean;
|
||
|
private WON: boolean;
|
||
|
constructor(simulator: Simulator, id: string, param: MultiRegisterParam) {
|
||
|
super(simulator, id, param);
|
||
|
this.regcount = param.count || 1;
|
||
|
this.r = [];
|
||
|
for (let a = 0; a < 4; ++a) {
|
||
|
this.pins.set('R' + (3 - a), new TriState(this, 40, a * 10 + 30));
|
||
|
this.pins.set('W' + (3 - a), new TriState(this, 40, a * 10 + 80));
|
||
|
this.pins.set('ALU_A' + (3 - a), new TriState(this, -40, a * 10 + 100));
|
||
|
this.pins.set('ALU_B' + (3 - a), new TriState(this, -40, a * 10 + 140));
|
||
|
}
|
||
|
this.pins.set('RON', new TriState(this, 40, 70));
|
||
|
this.pins.set('WON', new TriState(this, 40, 120));
|
||
|
this.pins.set('CLK', new TriState(this, 40, 0, undefined, { id: 'CLK' }));
|
||
|
this.pins.set('invCLK', new TriState(this, 40, 10));
|
||
|
for (let i = 0; i < 8; ++i) {
|
||
|
this.pins.set('D' + (7 - i), new TriState(this, 40, i * 10 - 80));
|
||
|
this.pins.set('A' + (7 - i), new TriState(this, -40, i * 10 - 80));
|
||
|
this.pins.set('B' + (7 - i), new TriState(this, -40, i * 10 + 10));
|
||
|
}
|
||
|
for (let b = 0; b < this.regcount; ++b) {
|
||
|
this.r[b] = 0;
|
||
|
}
|
||
|
this.oldCLK = false;
|
||
|
this.CLK = false;
|
||
|
this.RON = false;
|
||
|
this.WON = false;
|
||
|
}
|
||
|
setup(canvas: SVGElement) {
|
||
|
super.doSetup('multiregister', canvas);
|
||
|
}
|
||
|
|
||
|
update(): boolean {
|
||
|
let i;
|
||
|
let r;
|
||
|
let value;
|
||
|
// is R_ON set ? then send out to databus
|
||
|
if (this.RON) {
|
||
|
// which register is selected via R3...R0
|
||
|
r =
|
||
|
this.asint(this.getStateBool('R3'), 8) +
|
||
|
this.asint(this.getStateBool('R2'), 4) +
|
||
|
this.asint(this.getStateBool('R1'), 2) +
|
||
|
this.asint(this.getStateBool('R0'), 1);
|
||
|
value = this.r[r];
|
||
|
for (i = 0; i < 8; ++i) {
|
||
|
this.getPin('D' + i).setBool((value & (1 << i)) > 0 ? true : false);
|
||
|
}
|
||
|
}
|
||
|
const rising = this.CLK && this.oldCLK === false;
|
||
|
this.oldCLK = this.CLK;
|
||
|
// is W_ON set ? read from bus on raising clock edge
|
||
|
if (this.WON && rising) {
|
||
|
r =
|
||
|
this.asint(this.getStateBool('W3'), 8) +
|
||
|
this.asint(this.getStateBool('W2'), 4) +
|
||
|
this.asint(this.getStateBool('W1'), 2) +
|
||
|
this.asint(this.getStateBool('W0'), 1);
|
||
|
value =
|
||
|
this.asint(this.getStateBool('D7'), 128) +
|
||
|
this.asint(this.getStateBool('D6'), 64) +
|
||
|
this.asint(this.getStateBool('D5'), 32) +
|
||
|
this.asint(this.getStateBool('D4'), 16) +
|
||
|
this.asint(this.getStateBool('D3'), 8) +
|
||
|
this.asint(this.getStateBool('D2'), 4) +
|
||
|
this.asint(this.getStateBool('D1'), 2) +
|
||
|
this.asint(this.getStateBool('D0'), 1);
|
||
|
this.r[r] = value;
|
||
|
}
|
||
|
|
||
|
// output to alu A
|
||
|
const alu_a =
|
||
|
this.asint(this.getStateBool('ALU_A3'), 8) +
|
||
|
this.asint(this.getStateBool('ALU_A2'), 4) +
|
||
|
this.asint(this.getStateBool('ALU_A1'), 2) +
|
||
|
this.asint(this.getStateBool('ALU_A0'), 1);
|
||
|
//console.log("Alu A set to", alu_a);
|
||
|
value = this.r[alu_a];
|
||
|
for (i = 0; i < 8; ++i) {
|
||
|
this.getPin('A' + i).setBool((value & (1 << i)) > 0 ? true : false);
|
||
|
}
|
||
|
// output to alu B
|
||
|
const alu_b =
|
||
|
this.asint(this.getStateBool('ALU_B3'), 8) +
|
||
|
this.asint(this.getStateBool('ALU_B2'), 4) +
|
||
|
this.asint(this.getStateBool('ALU_B1'), 2) +
|
||
|
this.asint(this.getStateBool('ALU_B0'), 1);
|
||
|
value = this.r[alu_b];
|
||
|
for (i = 0; i < 8; ++i) {
|
||
|
this.getPin('B' + i).setBool((value & (1 << i)) > 0 ? true : false);
|
||
|
}
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
io() {
|
||
|
this.CLK = this.binary(this.getPin('CLK').getAndReset(), false);
|
||
|
this.getPin('invCLK').getAndReset();
|
||
|
this.RON = this.binary(this.getPin('RON').getAndReset(), false);
|
||
|
this.WON = this.binary(this.getPin('WON').getAndReset(), false);
|
||
|
for (let i = 0; i < 8; ++i) {
|
||
|
this.stateMapBool.set('D' + i, this.binary(this.getPin('D' + i).getAndReset(), true));
|
||
|
this.stateMapBool.set('A' + i, this.binary(this.getPin('A' + i).getAndReset(), true));
|
||
|
this.stateMapBool.set('B' + i, this.binary(this.getPin('B' + i).getAndReset(), true));
|
||
|
}
|
||
|
for (let a = 0; a < 4; ++a) {
|
||
|
this.stateMapBool.set('R' + a, this.binary(this.getPin('R' + a).getAndReset(), true));
|
||
|
this.stateMapBool.set('W' + a, this.binary(this.getPin('W' + a).getAndReset(), true));
|
||
|
this.stateMapBool.set('ALU_A' + a, this.binary(this.getPin('ALU_A' + a).getAndReset(), true));
|
||
|
this.stateMapBool.set('ALU_B' + a, this.binary(this.getPin('ALU_B' + a).getAndReset(), true));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
window.MultiRegister = MultiRegister;
|
||
|
}
|
||
|
|
||
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||
|
function MultiRegisterDepends() {
|
||
|
return 'LogicBase';
|
||
|
}
|