Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(VLIW): implement missing ALU instructions #165

Merged
merged 2 commits into from
May 7, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 10 additions & 6 deletions src/core/Common/FunctionalUnit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ export class FunctionalUnit {

constructor(
private _type: FunctionalUnitType,
private _latency: number = FunctionalUnitLantencies[_type]
private _latency: number = FunctionalUnitLantencies[_type],
) {
this._currentBlankTimeUnits = this._latency - 1;
}
Expand Down Expand Up @@ -112,7 +112,7 @@ export class FunctionalUnit {
this._currentBlankTimeUnits++;
this._currentBlankTimeUnits = Math.min(
this._currentBlankTimeUnits,
this._latency - 1
this._latency - 1,
); // it cannot be more than the latency
}

Expand All @@ -134,16 +134,20 @@ export class FunctionalUnit {
}

public getReadyInstructionUid(): number {
return this.getReadyInstruction()?.uid || -1;
}

public getReadyInstruction(): Instruction {
return this._instructions.length > 0 &&
this._instructions[0].blankTimeUnitsAhead == 0
? this._instructions[0].instruction.uid
: -1;
this._instructions[0].blankTimeUnitsAhead === 0
? this._instructions[0].instruction
: null;
}

// return the execution result of the instruction ready in the current cycle, or null if none
public executeReadyInstruction(
firstValue: number = 0,
secondValue: number = 0
secondValue: number = 0,
): FunctionalUnitResult {
if (
this._instructions.length == 0 ||
Expand Down
21 changes: 21 additions & 0 deletions src/core/VLIW/DependencyChecker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ export class DependencyChecker {
switch (operation.opcode) {
case Opcodes.ADD:
case Opcodes.ADDI:
case Opcodes.SUB:
case Opcodes.SRLV:
case Opcodes.SLLV:
case Opcodes.OR:
case Opcodes.AND:
case Opcodes.XOR:
case Opcodes.NOR:
if (checkGPR[operation.getOperand(0)].latency < functionalUnitLatencies[FunctionalUnitType.INTEGERSUM]) {
checkGPR[operation.getOperand(0)].latency = functionalUnitLatencies[FunctionalUnitType.INTEGERSUM];
checkGPR[operation.getOperand(0)].register = operation.id;
Expand Down Expand Up @@ -64,6 +71,13 @@ export class DependencyChecker {
switch (operation.opcode) {
case Opcodes.ADD:
case Opcodes.MULT:
case Opcodes.SUB:
case Opcodes.SRLV:
case Opcodes.SLLV:
case Opcodes.OR:
case Opcodes.AND:
case Opcodes.XOR:
case Opcodes.NOR:
if (((checkGPR[operation.getOperand(1)].latency > 0) && (checkGPR[operation.getOperand(1)].register < operation.id))
|| ((checkGPR[operation.getOperand(2)].latency > 0) && (checkGPR[operation.getOperand(2)].register < operation.id))) {
result = false;
Expand Down Expand Up @@ -119,6 +133,13 @@ export class DependencyChecker {
switch (operation.opcode) {
case Opcodes.ADD:
case Opcodes.MULT:
case Opcodes.SUB:
case Opcodes.SRLV:
case Opcodes.SLLV:
case Opcodes.OR:
case Opcodes.AND:
case Opcodes.XOR:
case Opcodes.NOR:
result = NaTGP[operation.getOperand(1)] || NaTGP[operation.getOperand(2)];
break;
case Opcodes.ADDI:
Expand Down
134 changes: 67 additions & 67 deletions src/core/VLIW/VLIW.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Machine } from '../Common/Machine';
import { Opcodes } from '../Common/Opcodes';
import { VLIWCode } from './VLIWCode';
import { FunctionalUnit, FunctionalUnitType, FUNCTIONALUNITTYPESQUANTITY } from '../Common/FunctionalUnit';
import { FunctionalUnit, FunctionalUnitResult, FunctionalUnitType, FUNCTIONALUNITTYPESQUANTITY } from '../Common/FunctionalUnit';
import { DependencyChecker, Check } from './DependencyChecker';
import { VLIWError } from './VLIWError';
import { VLIWOperation } from './VLIWOperation';
Expand Down Expand Up @@ -150,15 +150,29 @@ export class VLIW extends Machine {
pending = true;
}


let execution = this.functionalUnit[i][j].executeReadyInstruction();
let operation: any = (execution != null) ? execution.instruction : null;

if (operation != null) {
if (this._predR[operation.getPred()]) {
this.runOperation(operation, this.functionalUnit[i][j]);
}
const instToExecute = this.functionalUnit[i][
j
].getReadyInstruction() as VLIWOperation;

if (instToExecute && this._predR[instToExecute.getPred()]) {
const registerFile = instToExecute.isDestinyRegisterFloat()
? this._fpr
: this._gpr;
const firstOperand =
registerFile.content[
instToExecute.getFirstOperandRegister()
];
const secondOperand = instToExecute.hasImmediateOperand()
? instToExecute.getImmediateOperand()
: registerFile.content[
instToExecute.getSecondOperandRegister()
];
const execution = this.functionalUnit[i][
j
].executeReadyInstruction(firstOperand, secondOperand);
this.runOperation(execution, this.functionalUnit[i][j]);
}

this.functionalUnit[i][j].tic();
}
}
Expand Down Expand Up @@ -233,65 +247,51 @@ export class VLIW extends Machine {
this._predR[0] = true;
}

private runOperation(operation: VLIWOperation, functionalUnit: FunctionalUnit) {
switch (operation.opcode) {
case Opcodes.ADD:
this._gpr.setContent(operation.getOperand(0), this._gpr.content[operation.getOperand(1)] + this._gpr.content[operation.getOperand(2)], true);
break;
case Opcodes.MULT:
this._gpr.setContent(operation.getOperand(0), this._gpr.content[operation.getOperand(1)] * this._gpr.content[operation.getOperand(2)], true);
break;
case Opcodes.ADDI:
this._gpr.setContent(operation.getOperand(0), this._gpr.content[operation.getOperand(1)] + operation.getOperand(2), true);
break;
case Opcodes.ADDF:
this._fpr.setContent(operation.getOperand(0), this._fpr.content[operation.getOperand(1)] + this._fpr.content[operation.getOperand(2)], true);
break;
case Opcodes.MULTF:
this._fpr.setContent(operation.getOperand(0), this._fpr.content[operation.getOperand(1)] * this._fpr.content[operation.getOperand(2)], true);
break;
case Opcodes.SW:
this._memory.setData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._gpr.content[operation.getOperand(0)]);
break;
case Opcodes.SF:
this._memory.setData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._fpr.content[operation.getOperand(0)]);
break;
case Opcodes.LW: {
const datumInteger = this._memory.getData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1));

//hack: as we dont have a well made error handling, intercept the error and just throw it
if (datumInteger instanceof Error) {
throw datumInteger;
}

if (this._cache && !this._cache.success) {
functionalUnit.stall(this._memoryFailLatency - functionalUnit.latency);
}

this._gpr.setContent(operation.getOperand(0), datumInteger, true);
this._NaTGP[operation.getOperand(0)] = false;
break;
}
case Opcodes.LF: {
const datumFloat = this._memory.getData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1));

//hack: as we dont have a well made error handling, intercept the error and just throw it
if (datumFloat instanceof Error) {
throw datumFloat;
}

if (this._cache && !this._cache.success) {
functionalUnit.stall(this._memoryFailLatency - functionalUnit.latency);
}

this._fpr.setContent(operation.getOperand(0), datumFloat, true);
this._NaTFP[operation.getOperand(0)] = false;
break;
}
default:
break;
private runOperation(execution: FunctionalUnitResult, functionalUnit: FunctionalUnit) {
const operation = execution.instruction;
const registerFile = operation.isDestinyRegisterFloat()
? this._fpr
: this._gpr;

if (operation.isLoadInstruction()) {
// load and stores are a special cases, because they need to access the memory
const natFile = operation.isDestinyRegisterFloat()
? this._NaTFP
: this._NaTGP;
const datum = this._memory.getData(
this._gpr.content[operation.getSecondOperandRegister()] +
operation.getAddressOperand(),
);

//hack: as we dont have a well made error handling, intercept the error and just throw it
if (datum instanceof Error) {
throw datum;
}

if (this._cache && !this._cache.success) {
functionalUnit.stall(
this._memoryFailLatency - functionalUnit.latency,
);
}

registerFile.setContent(operation.getDestinyRegister(), datum, true);
natFile[operation.getDestinyRegister()] = false;
} else if (operation.isStoreInstruction()) {
this._memory.setData(
this._gpr.content[operation.getSecondOperandRegister()] +
operation.getAddressOperand(),
registerFile.content[operation.getFirstOperandRegister()],
);
} else {
// if the operation is not a load or store, then it is a register operation
registerFile.setContent(
operation.getDestinyRegister(),
execution.result,
true,
);
}
this._gpr.setContent(0, 0, true);

// this is a old undocumented hack probably to avoid the 0 predication register to be set to false
this._predR[0] = true;
}

Expand Down
43 changes: 43 additions & 0 deletions src/test/functional/VLIW/shift.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import { expect, beforeEach, test } from "vitest";
import { VLIW } from "../../../core/VLIW/VLIW";
import { VLIWCode } from "../../../core/VLIW/VLIWCode";
import { Code } from "../../../core/Common/Code";
import { VLIWError } from "../../../core/VLIW/VLIWError";
import { codeInput, vliwCodeInput, resultContent } from "../code/despl";

const context: { code: VLIWCode; superscalarCode: Code; machine: VLIW } = {
code: null,
superscalarCode: null,
machine: null,
};

beforeEach(() => {
context.code = new VLIWCode();
context.superscalarCode = new Code();
context.machine = new VLIW();
context.machine.init(true);
});

test("Despl.pla is executed properly", () => {
// Load code
context.superscalarCode.load(codeInput);
context.code.load(vliwCodeInput, context.superscalarCode);
context.machine.code = context.code;

// Execute code
while (context.machine.tic() !== VLIWError.ENDEXE) {}

// Check where the program counter is
expect(context.machine.pc).toBe(8);

// Check the result
const resultBaseAddress = 1;
const result = context.machine.gpr.content.slice(
resultBaseAddress,
resultBaseAddress + resultContent.length,
);
expect(result).toStrictEqual(resultContent);

// Check the cycles
expect(context.machine.status.cycle).toBe(10);
});
10 changes: 10 additions & 0 deletions src/test/functional/code/despl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,14 @@ AND R8 R5 R6
NOR R9 R5 R6
XOR R10 R5 R6`;

export const vliwCodeInput = `
2 0 0 0 0 1 0 1 0
0
2 2 0 0 0 3 0 1 0
2 4 0 0 0 5 0 1 0
0
2 5 0 0 0 6 0 1 0
2 7 0 0 0 8 0 1 0
1 9 0 0 0`.trim();

export const resultContent = [3, 2, 12, 0, 11, 6, 15, 2, -16, 13];
endes0 marked this conversation as resolved.
Show resolved Hide resolved