From 15af20a06c30518fbac7e7305ed4b72285968c53 Mon Sep 17 00:00:00 2001 From: endes0 Date: Sun, 28 Apr 2024 16:41:16 +0100 Subject: [PATCH] feat: implement direct-mapped cache, cache config modal (#158) * refactor(core): new cache aproach * feat(core): implement direct mapped cache * add cache configs to SuperscalarConfigModal and fix NoCache * integrate cache changes into the VLIW * fix(interface): memory not showing * fix(tests): replace memory accesses to cache * tests(core): add unit cache tests and fix DirectCache (TLDR: tests are important) * remove unecesarry import * refacfor: apply PR suggestions * refact(core): first working implementation of cache using proxies * refact(core): the cache proxies the memory access funtions * fix(cache): remove a strange import inserted by copilot --- public/locales/en/common.json | 8 +- public/locales/es/common.json | 8 +- src/core/Common/Cache.ts | 122 ++++ src/core/Common/Machine.ts | 18 +- src/core/Common/Memory.ts | 42 +- src/core/Superscalar/Superscalar.ts | 8 +- src/core/VLIW/VLIW.ts | 23 +- src/integration/superscalar-integration.ts | 106 ++- src/integration/vliw-integration.ts | 102 ++- .../Common/Modal/BatchModalComponent.tsx | 67 +- .../modal/SuperscalarConfigModal.tsx | 290 +++++--- .../VLIW/modal/BatchModalComponent.tsx | 67 +- .../VLIW/modal/VLIWConfigModalComponent.tsx | 678 +++++++++++------- src/interface/utils/constants.ts | 12 +- .../Superscalar/iteratelist.spec.ts | 4 +- src/test/functional/Superscalar/loop.spec.ts | 18 +- .../speculativenosideeffects.spec.ts | 2 +- src/test/functional/VLIW/loop.spec.ts | 36 +- src/test/functional/VLIW/multiwayvliw.spec.ts | 18 +- src/test/unit/core/Common/Cache.spec.ts | 118 +++ 20 files changed, 1123 insertions(+), 624 deletions(-) create mode 100644 src/core/Common/Cache.ts create mode 100644 src/test/unit/core/Common/Cache.spec.ts diff --git a/public/locales/en/common.json b/public/locales/en/common.json index 407ca6e8..61f0a54a 100644 --- a/public/locales/en/common.json +++ b/public/locales/en/common.json @@ -76,7 +76,13 @@ "quantity": "Quantity", "cacheFault": "Cache fault", "issue": "Issue", - "default": "Default values" + "default": "Default values", + "cacheType": "Cache type", + "cacheLines": "Cache lines", + "cacheBlocks": "Cache blocks", + "noCache": "Without cache", + "directCache": "Direct-mapped", + "randomCache": "Random" }, "vliwModal": { "name": "VLIW Configuration", diff --git a/public/locales/es/common.json b/public/locales/es/common.json index 816c38fa..e04175a4 100644 --- a/public/locales/es/common.json +++ b/public/locales/es/common.json @@ -76,7 +76,13 @@ "quantity": "Cantidad", "cacheFault": "Fallo de caché", "issue": "Emisión", - "default": "Valores por defecto" + "default": "Valores por defecto", + "cacheType": "Tipo de caché", + "cacheLines": "Tamaño de caché", + "cacheBlocks": "Bloques de caché", + "noCache": "Sin caché", + "directCache": "Mapeado directo", + "randomCache": "Aleatoria" }, "vliwModal": { "name": "Configuración VLIW", diff --git a/src/core/Common/Cache.ts b/src/core/Common/Cache.ts new file mode 100644 index 00000000..d11d3db7 --- /dev/null +++ b/src/core/Common/Cache.ts @@ -0,0 +1,122 @@ +import type { Memory } from "./Memory"; + +export enum CacheType { + NO_CACHE = "NO_CACHE", + RANDOM_CACHE = "RANDOM_CACHE", + DIRECT_CACHE = "DIRECT_CACHE", +} + +export interface Datum { + value: number; + got: boolean; +} + +export abstract class Cache { + public abstract success: boolean; + public abstract getHandler: ProxyHandler; + public abstract setHandler: ProxyHandler; +} + +export class RandomCache extends Cache { + public success = true; + public getHandler: ProxyHandler; + public setHandler: ProxyHandler = {}; + constructor(public faultChance: number) { + super(); + + this.getHandler = { + apply: this.applyToGetData.bind(this), + }; + } + + public applyToGetData( + target: typeof Memory.prototype.getData, + thisArg: any, + args: any[], + ) { + this.success = this.faultChance < Math.random(); + + return Reflect.apply(target, thisArg, args); + } +} + +export class DirectCache extends Cache { + public success = true; + public getHandler: ProxyHandler; + public setHandler: ProxyHandler; + private readonly blocks_tags: number[]; + private block_size: number; + + constructor( + private _blocks: number, // number of blocks + _size: number, + ) { + super(); + + // Calculate the block size + this.block_size = Math.floor(_size / _blocks); + + // Initializa the blocks tags to -1 + this.blocks_tags = Array(_blocks).fill(-1); + + this.getHandler = { + apply: this.applyToGetData.bind(this), + }; + + this.setHandler = { + apply: this.applyToSetData.bind(this), + }; + } + + public applyToGetData( + target: typeof Memory.prototype.getData, + thisArg: any, + args: any[], + ) { + const address = args[0]; + + // get the tag of the address + const tag = Math.floor(address / this.block_size); + + // check if the tag is in the cache + const faultOccurred = this.blocks_tags[tag % this._blocks] !== tag; + this.success = !faultOccurred; + + // set the tag in the cache + this.blocks_tags[tag % this._blocks] = tag; + + return Reflect.apply(target, thisArg, args); + } + + public applyToSetData( + target: typeof Memory.prototype.getData, + thisArg: any, + args: any[], + ) { + const address = args[0]; + + // get the tag of the address + const tag = Math.floor(address / this.block_size); + + // set the tag in the cache + this.blocks_tags[tag % this._blocks] = tag; + + return Reflect.apply(target, thisArg, args); + } +} + +export function createCache( + cacheType: CacheType, + ...args: number[] +): RandomCache | DirectCache | null { + switch (cacheType) { + case CacheType.NO_CACHE: + return null; + case CacheType.RANDOM_CACHE: + return new RandomCache(args[2]); + case CacheType.DIRECT_CACHE: + return new DirectCache(args[0], args[1]); + default: + throw new Error("Invalid cache type"); + } +} diff --git a/src/core/Common/Machine.ts b/src/core/Common/Machine.ts index 494fc12e..91006462 100644 --- a/src/core/Common/Machine.ts +++ b/src/core/Common/Machine.ts @@ -5,6 +5,7 @@ import { FunctionalUnitType, FunctionalUnitNumbers, } from "./FunctionalUnit"; +import { Cache } from "./Cache"; import { Memory } from "./Memory"; const MACHINE_REGISTER_SIZE = 64; @@ -31,6 +32,7 @@ export class Machine { protected _functionalUnit: FunctionalUnit[][]; protected _memory: Memory; + protected _cache: Cache; protected _pc: number; protected _status: MachineStatus; @@ -58,6 +60,16 @@ export class Machine { this._memory = value; } + public get cache(): Cache { + return this._cache; + } + + public set cache(value: Cache) { + this._cache = value; + // Proxy the memory access to the cache + this.resetContent(); + } + public get pc(): number { return this._pc; } @@ -136,7 +148,11 @@ export class Machine { public resetContent() { this._gpr.setAllContent(0); this._fpr.setAllContent(0); - this.memory = new Memory(this.memory.size, this.memory.faultChance); + this.memory = new Memory(Machine.MEMORY_SIZE); + if (this.cache) { + this.memory.getData = new Proxy(this.memory.getData, this.cache.getHandler); + this.memory.setData = new Proxy(this.memory.setData, this.cache.setHandler); + } } public changeFunctionalUnitLatency( diff --git a/src/core/Common/Memory.ts b/src/core/Common/Memory.ts index 7ee4c129..57f90af2 100644 --- a/src/core/Common/Memory.ts +++ b/src/core/Common/Memory.ts @@ -1,31 +1,23 @@ -export interface Datum { - value: number; - got: boolean; -} - /** * Returns an Error when target method is called with * a non-positive `address: number` argument. */ -export const forcePositiveAddresses = (address: number): void | Error => { +export const forcePositiveAddresses = (address: number): Error | undefined => { if (address < 0) { return Error("Negative numbers are invalid as addresses"); } }; -export class Memory implements Iterable { - private readonly data: Datum[]; +export class Memory implements Iterable { + private readonly data: number[]; - constructor(size: number, public faultChance: number = 0.0) { + constructor(size: number) { // Initialize clean data array with `size` Datum slots. - this.data = Array.from(Array(size).keys()).map((n) => ({ - value: 0, - got: true, - })); + this.data = Array(size).fill(0); } // Memory iterator - [Symbol.iterator](): IterableIterator { + [Symbol.iterator](): IterableIterator { return this.data.values(); } @@ -37,27 +29,17 @@ export class Memory implements Iterable { return this.data.length; } - public getFaultyDatum(address: number): Datum | Error { - let error = forcePositiveAddresses(address); + public getData(address: number): Error | number { + const error = forcePositiveAddresses(address); if (error) return error; - const datum = this.data[address]; - - const faultOccurred = this.faultChance > Math.random(); - - // This will flip 'got' to false if a fault occurred or to true if there was a fault the last time. - // So effectively, we will evite getting the same fault twice in a row. - if (faultOccurred || !datum.got) { - datum.got = !datum.got; - } - - return { ...datum }; + return this.data[address]; } - public setDatum(address: number, value: number): void | Error { - let error = forcePositiveAddresses(address); + public setData(address: number, value: number): Error | undefined { + const error = forcePositiveAddresses(address); if (error) return error; - this.data[address] = { ...this.data[address], value }; + this.data[address] = value; } } diff --git a/src/core/Superscalar/Superscalar.ts b/src/core/Superscalar/Superscalar.ts index 7e8584a6..8b7236da 100644 --- a/src/core/Superscalar/Superscalar.ts +++ b/src/core/Superscalar/Superscalar.ts @@ -492,7 +492,7 @@ export class Superscalar extends Machine { // load and stores are a special cases, because they need to access the memory if (inst.isLoadInstruction()) { - let a = this.memory.getFaultyDatum( + const a = this.memory.getData( this._reserveStations[type].getAddressOperand(instUid) ); @@ -501,8 +501,8 @@ export class Superscalar extends Machine { throw a; } - resul = a.value; - if (!a.got) { + resul = a; + if (this.cache && !this.cache.success) { this.functionalUnit[type][num].stall( this.memoryFailLatency - this.functionalUnit[type][num].latency ); @@ -582,7 +582,7 @@ export class Superscalar extends Machine { this._currentCommitedInstrs = new Array(); for (let i = 0; i < this.issue; i++) { if (this._reorderBuffer.canCommitStoreInstruction()) { - this.memory.setDatum( + this.memory.setData( this._reorderBuffer.getResultAddress(), this._reorderBuffer.getResultValue() ); diff --git a/src/core/VLIW/VLIW.ts b/src/core/VLIW/VLIW.ts index 74c06ab0..267dc9ab 100644 --- a/src/core/VLIW/VLIW.ts +++ b/src/core/VLIW/VLIW.ts @@ -4,7 +4,6 @@ import { VLIWCode } from './VLIWCode'; import { FunctionalUnit, FunctionalUnitType, FUNCTIONALUNITTYPESQUANTITY } from '../Common/FunctionalUnit'; import { DependencyChecker, Check } from './DependencyChecker'; import { VLIWError } from './VLIWError'; -import { Datum } from '../Common/Memory'; import { VLIWOperation } from './VLIWOperation'; export class VLIW extends Machine { @@ -252,41 +251,43 @@ export class VLIW extends Machine { 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.setDatum(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._gpr.content[operation.getOperand(0)]); + this._memory.setData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._gpr.content[operation.getOperand(0)]); break; case Opcodes.SF: - this._memory.setDatum(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._fpr.content[operation.getOperand(0)]); + this._memory.setData(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1), this._fpr.content[operation.getOperand(0)]); break; - case Opcodes.LW: - let datumInteger = this._memory.getFaultyDatum(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1)); + 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 (!datumInteger.got) { + if (this._cache && !this._cache.success) { functionalUnit.stall(this._memoryFailLatency - functionalUnit.latency); } - this._gpr.setContent(operation.getOperand(0), datumInteger.value, true); + this._gpr.setContent(operation.getOperand(0), datumInteger, true); this._NaTGP[operation.getOperand(0)] = false; break; - case Opcodes.LF: - let datumFloat = this._memory.getFaultyDatum(this._gpr.content[operation.getOperand(2)] + operation.getOperand(1)); + } + 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 (!datumFloat.got) { + if (this._cache && !this._cache.success) { functionalUnit.stall(this._memoryFailLatency - functionalUnit.latency); } - this._fpr.setContent(operation.getOperand(0), datumFloat.value, true); + this._fpr.setContent(operation.getOperand(0), datumFloat, true); this._NaTFP[operation.getOperand(0)] = false; break; + } default: break; } diff --git a/src/integration/superscalar-integration.ts b/src/integration/superscalar-integration.ts index 095bc39c..29c72580 100644 --- a/src/integration/superscalar-integration.ts +++ b/src/integration/superscalar-integration.ts @@ -32,6 +32,7 @@ import { MAX_HISTORY_SIZE } from '../interface/reducers/machine'; import { t } from 'i18next'; import { Code } from '../core/Common/Code'; +import { createCache } from '../core/Common/Cache'; import { SuperscalarStatus } from '../core/Superscalar/SuperscalarEnums'; @@ -50,8 +51,6 @@ export class SuperscalarIntegration extends MachineIntegration { finishedExecution = false; executing = false; replications = 0; - cacheFailPercentage = 0; - cacheFailLatency = 0; stats = new Stats(); batchStats = new StatsAgregator(); @@ -98,7 +97,7 @@ export class SuperscalarIntegration extends MachineIntegration { nextReorderBufferMapperCycle([this.superscalar.reorderBuffer.getVisualRegisterMap(false), this.superscalar.reorderBuffer.getVisualRegisterMap(true)]), nextReorderBufferCycle(this.superscalar.reorderBuffer), nextRegistersCycle([this.superscalar.gpr.content, this.superscalar.fpr.content]), - nextMemoryCycle(Array.from(this.superscalar.memory).map(d => d.value)), + nextMemoryCycle(Array.from(this.superscalar.memory)), nextCycle(this.superscalar.status.cycle), nextTotalCommited(this.stats.getCommitedAndDiscarded()), nextInstructionsCommited(this.stats.getCommitedPercentagePerInstruction()), @@ -231,12 +230,10 @@ export class SuperscalarIntegration extends MachineIntegration { const results = []; this.batchStats = new StatsAgregator(); for (let i = 0; i < this.replications; i++) { - let code = Object.assign(new Code(), this.superscalar.code); + const code = Object.assign(new Code(), this.superscalar.code); this.superExe(); this.superscalar.code = code; - //TODO: check this data, seems to be inverted - this.superscalar.memory.faultChance = this.cacheFailPercentage / 100; - this.superscalar.memoryFailLatency = this.cacheFailLatency; + // Load memory content if (this.contentIntegration) { @@ -301,9 +298,10 @@ export class SuperscalarIntegration extends MachineIntegration { if (this.superscalar.status.cycle > 0) { return; } - Object.keys(data).forEach(key => { - this.superscalar.memory.setDatum(+key, data[key]); - }); + + for (const key in data) { + this.superscalar.memory.setData(+key, data[key]); + } } setFpr = (data: { [k: number]: number }) => { @@ -346,36 +344,84 @@ export class SuperscalarIntegration extends MachineIntegration { } saveSuperConfig = (superConfig) => { - // TODO: enforce this through a unique map so that we can overwrite the config directly - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.INTEGERSUM, +superConfig.integerSumQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.INTEGERSUM, +superConfig.integerSumLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.INTEGERSUM, + +superConfig.integerSumQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.INTEGERSUM, + +superConfig.integerSumLatency, + ); + + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.INTEGERMULTIPLY, + +superConfig.integerMultQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.INTEGERMULTIPLY, + +superConfig.integerMultLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.INTEGERMULTIPLY, +superConfig.integerMultQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.INTEGERMULTIPLY, +superConfig.integerMultLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGSUM, + +superConfig.floatingSumQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGSUM, + +superConfig.floatingSumLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.FLOATINGSUM, +superConfig.floatingSumQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.FLOATINGSUM, +superConfig.floatingSumLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGSUM, + +superConfig.floatingSumQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGSUM, + +superConfig.floatingSumLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.FLOATINGSUM, +superConfig.floatingSumQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.FLOATINGSUM, +superConfig.floatingSumLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGMULTIPLY, + +superConfig.floatingMultQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGMULTIPLY, + +superConfig.floatingMultLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.FLOATINGMULTIPLY, +superConfig.floatingMultQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.FLOATINGMULTIPLY, +superConfig.floatingMultLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.JUMP, + +superConfig.jumpQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.JUMP, + +superConfig.jumpLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.JUMP, +superConfig.jumpQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.JUMP, +superConfig.jumpLatency); + this.superscalar.changeFunctionalUnitNumber( + FunctionalUnitType.MEMORY, + +superConfig.memoryQuantity, + ); + this.superscalar.changeFunctionalUnitLatency( + FunctionalUnitType.MEMORY, + +superConfig.memoryLatency, + ); - this.superscalar.changeFunctionalUnitNumber(FunctionalUnitType.MEMORY, +superConfig.memoryQuantity); - this.superscalar.changeFunctionalUnitLatency(FunctionalUnitType.MEMORY, +superConfig.memoryLatency); - this.superscalar.issue = +superConfig.issueGrade; + + this.superscalar.cache = createCache( + superConfig.cacheType, + +superConfig.cacheBlocks, + +superConfig.cacheLines, + +superConfig.cacheFailPercentage / 100, + ); + this.superscalar.memoryFailLatency = +superConfig.cacheFailLatency; + this.resetMachine(); } - setBatchMode = (replications: number, cacheFailLatency, cacheFailPercentage) => { + setBatchMode = (replications: number) => { this.replications = replications; - this.cacheFailLatency = cacheFailLatency; - this.cacheFailPercentage = cacheFailPercentage; } private resetMachine() { @@ -399,8 +445,6 @@ export class SuperscalarIntegration extends MachineIntegration { private clearBatchStateEffects() { // Post launch machine clean - this.superscalar.memory.faultChance = 0; - this.superscalar.memoryFailLatency = 0; this.resetMachine(); } } diff --git a/src/integration/vliw-integration.ts b/src/integration/vliw-integration.ts index 887ba6fb..8f62070a 100644 --- a/src/integration/vliw-integration.ts +++ b/src/integration/vliw-integration.ts @@ -24,11 +24,13 @@ import { VLIW } from '../core/VLIW/VLIW'; import { VLIWCode } from '../core/VLIW/VLIWCode'; import { VLIWError } from '../core/VLIW/VLIWError'; import { VLIWOperation } from '../core/VLIW/VLIWOperation'; +import { createCache } from '../core/Common/Cache'; import { nextNatFprCycle, nextNatGprCycle, nextPredicateCycle } from '../interface/actions/predicate-nat-actions'; import { displayBatchResults } from '../interface/actions/modals'; import { Stats } from '../stats/stats'; import { StatsAgregator } from '../stats/aggregator'; +import { FunctionalUnitType } from '@/core/Common/FunctionalUnit'; export class VLIWIntegration extends MachineIntegration { // Global objects for binding React to the View @@ -40,8 +42,6 @@ export class VLIWIntegration extends MachineIntegration { finishedExecution = false; executing = false; replications = 0; - cacheFailPercentage = 0; - cacheFailLatency = 0; stats = new Stats(); batchStats = new StatsAgregator(); @@ -59,7 +59,7 @@ export class VLIWIntegration extends MachineIntegration { nextVLIWHeaderTableCycle(this.vliw.functionalUnitNumbers), nextVLIWExecutionTableCycle(this.vliw.code.instructions, this.vliw.functionalUnitNumbers), nextRegistersCycle([this.vliw.gpr.content, this.vliw.fpr.content]), - nextMemoryCycle(Array.from(this.vliw.memory).map(d => d.value)), + nextMemoryCycle(Array.from(this.vliw.memory)), nextCycle(this.vliw.status.cycle), currentPC(this.vliw.pc), nextNatFprCycle(this.vliw.getNaTFP()), @@ -229,8 +229,6 @@ export class VLIWIntegration extends MachineIntegration { let code = Object.assign(new VLIWCode(), this.vliw.code); this.vliwExe(); this.vliw.code = code; - this.vliw.memory.faultChance = this.cacheFailPercentage / 100; - this.vliw.memoryFailLatency = this.cacheFailLatency; // Load memory content if (this.contentIntegration) { @@ -296,9 +294,9 @@ export class VLIWIntegration extends MachineIntegration { if (this.vliw.status.cycle > 0) { return; } - Object.keys(data).forEach(key => { - this.vliw.memory.setDatum(+key, data[key]); - }); + for (const key in data) { + this.vliw.memory.setData(+key, data[key]); + } } setFpr = (data: { [k: number]: number }) => { @@ -351,23 +349,82 @@ export class VLIWIntegration extends MachineIntegration { } saveVliwConfig = (vliwConfig) => { - const vliwConfigKeys = Object.keys(vliwConfig); - - for (let i = 0; i < vliwConfigKeys.length; i++) { - if (i % 2 === 0) { - this.vliw.changeFunctionalUnitNumber(i / 2, - +vliwConfig[vliwConfigKeys[i]]); - } else { - this.vliw.changeFunctionalUnitLatency((i - 1) / 2, - +vliwConfig[vliwConfigKeys[i]]); - } - } + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.INTEGERSUM, + +vliwConfig.integerSumQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.INTEGERSUM, + +vliwConfig.integerSumLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.INTEGERMULTIPLY, + +vliwConfig.integerMultQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.INTEGERMULTIPLY, + +vliwConfig.integerMultLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGSUM, + +vliwConfig.floatingSumQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGSUM, + +vliwConfig.floatingSumLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGSUM, + +vliwConfig.floatingSumQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGSUM, + +vliwConfig.floatingSumLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.FLOATINGMULTIPLY, + +vliwConfig.floatingMultQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.FLOATINGMULTIPLY, + +vliwConfig.floatingMultLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.JUMP, + +vliwConfig.jumpQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.JUMP, + +vliwConfig.jumpLatency, + ); + + this.vliw.changeFunctionalUnitNumber( + FunctionalUnitType.MEMORY, + +vliwConfig.memoryQuantity, + ); + this.vliw.changeFunctionalUnitLatency( + FunctionalUnitType.MEMORY, + +vliwConfig.memoryLatency, + ); + + this.vliw.cache = createCache( + vliwConfig.cacheType, + +vliwConfig.cacheBlocks, + +vliwConfig.cacheLines, + +vliwConfig.cacheFailPercentage / 100, + ); + this.vliw.memoryFailLatency = +vliwConfig.cacheFailLatency; + + this.resetMachine(); } - setBatchMode = (replications: number, cacheFailLatency, cacheFailPercentage) => { + setBatchMode = (replications: number) => { this.replications = replications; - this.cacheFailLatency = cacheFailLatency; - this.cacheFailPercentage = cacheFailPercentage; } private resetMachine() { @@ -387,7 +444,6 @@ export class VLIWIntegration extends MachineIntegration { private clearBatchStateEffects() { // Post launch machine clean - this.vliw.memory.faultChance = 0; this.vliw.memoryFailLatency = 0; this.resetMachine(); } diff --git a/src/interface/components/Common/Modal/BatchModalComponent.tsx b/src/interface/components/Common/Modal/BatchModalComponent.tsx index 04c9f4b0..319f0de3 100644 --- a/src/interface/components/Common/Modal/BatchModalComponent.tsx +++ b/src/interface/components/Common/Modal/BatchModalComponent.tsx @@ -12,18 +12,10 @@ class BatchModalComponent extends React.Component { super(props); this.state = { replications: 10, - cacheFailPercentage: 30, - cacheFailLatency: 9 }; this.close = this.close.bind(this); this.setOptions = this.setOptions.bind(this); this.handleChange = this.handleChange.bind(this); - this.handleCachePercentageChange = this.handleCachePercentageChange.bind( - this - ); - this.handleCacheFailLatencyChange = this.handleCacheFailLatencyChange.bind( - this - ); } @@ -33,34 +25,17 @@ class BatchModalComponent extends React.Component { } handleChange(event) { - let newState = { ...this.state }; + const newState = { ...this.state }; newState.replications = event.target.value; this.setState(newState); } setOptions() { - SuperscalarIntegration.setBatchMode( - this.state.replications, - this.state.cacheFailLatency, - this.state.cacheFailPercentage - - ); + SuperscalarIntegration.setBatchMode(this.state.replications); this.close(); SuperscalarIntegration.makeBatchExecution(); } - handleCachePercentageChange(event) { - let newState = { ...this.state }; - newState.cacheFailPercentage = event.target.value; - this.setState(newState); - } - - handleCacheFailLatencyChange(event) { - let newState = { ...this.state }; - newState.cacheFailLatency = event.target.value; - this.setState(newState); - } - render() { return ( @@ -88,44 +63,6 @@ class BatchModalComponent extends React.Component { /> -
- -
- -
-
-
- -
- -
-
diff --git a/src/interface/components/Superscalar/modal/SuperscalarConfigModal.tsx b/src/interface/components/Superscalar/modal/SuperscalarConfigModal.tsx index 9c6975d3..f29a4bb5 100644 --- a/src/interface/components/Superscalar/modal/SuperscalarConfigModal.tsx +++ b/src/interface/components/Superscalar/modal/SuperscalarConfigModal.tsx @@ -1,13 +1,13 @@ import * as React from "react"; import { - Alert, - Button, - Col, - Container, - Form, - Modal, - Row, - Stack, + Alert, + Button, + Col, + Container, + Form, + Modal, + Row, + Stack, } from "react-bootstrap"; import { type WithTranslation, withTranslation } from "react-i18next"; import { connect } from "react-redux"; @@ -15,62 +15,72 @@ import { bindActionCreators, type Dispatch, type UnknownAction } from "redux"; import { toggleSuperConfigModal } from "../../../actions/modals"; import SuperscalarIntegration from "../../../../integration/superscalar-integration"; -import { SUPERSCALAR_CONFIG } from "../../../utils/constants"; +import { BATCH_CONFIG, SUPERSCALAR_CONFIG } from "../../../utils/constants"; +import { CacheType } from "@/core/Common/Cache"; import type { GlobalState } from "../../../reducers"; const mapStateToProps = (state: GlobalState) => { - return { - isSuperscalarConfigModalShown: state.Ui.isSuperConfigModalOpen, - }; + return { + isSuperscalarConfigModalShown: state.Ui.isSuperConfigModalOpen, + }; }; const mapDispatchToProps = (dispatch: Dispatch) => { - return { actions: bindActionCreators({ toggleSuperConfigModal }, dispatch) }; + return { actions: bindActionCreators({ toggleSuperConfigModal }, dispatch) }; }; export type SuperscalarConfigModalProps = WithTranslation & - ReturnType & - ReturnType; + ReturnType & + ReturnType; export const SuperscalarConfigModal: React.FC = ({ - isSuperscalarConfigModalShown, - actions, - t, + isSuperscalarConfigModalShown, + actions, + t, }: SuperscalarConfigModalProps) => { - const defaultConfig = { - integerSumQuantity: 2, - integerSumLatency: 1, - integerMultQuantity: 2, - integerMultLatency: 2, - floatingSumQuantity: 2, - floatingSumLatency: 4, - floatingMultQuantity: 2, - floatingMultLatency: 6, - memoryQuantity: 2, - memoryLatency: 4, - jumpQuantity: 1, - jumpLatency: 2, - issueGrade: 4, - }; + const defaultConfig = { + integerSumQuantity: 2, + integerSumLatency: 1, + integerMultQuantity: 2, + integerMultLatency: 2, + floatingSumQuantity: 2, + floatingSumLatency: 4, + floatingMultQuantity: 2, + floatingMultLatency: 6, + memoryQuantity: 2, + memoryLatency: 4, + jumpQuantity: 1, + jumpLatency: 2, + issueGrade: 4, + cacheType: CacheType.NO_CACHE, + cacheFailPercentage: 30, + cacheFailLatency: 9, + cacheBlocks: 4, + cacheLines: 16, + }; - const [config, setConfig] = React.useState(defaultConfig); + const [config, setConfig] = React.useState(defaultConfig); const saveConfig = () => { SuperscalarIntegration.saveSuperConfig(config); closeModal(); }; - const updateConfig = (event) => { - setConfig({ ...config, [event.target.name]: Number(event.target.value) }); - }; + const updateNumConfig = (event) => { + setConfig({ ...config, [event.target.name]: Number(event.target.value) }); + }; - const setDefaultConfig = () => { - setConfig(defaultConfig); - }; + const updateStrConfig = (event) => { + setConfig({ ...config, [event.target.name]: event.target.value }); + }; - const closeModal = () => { - actions.toggleSuperConfigModal(false); - }; + const setDefaultConfig = () => { + setConfig(defaultConfig); + }; + + const closeModal = () => { + actions.toggleSuperConfigModal(false); + }; return ( @@ -106,7 +116,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.integerSumQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -118,7 +128,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.integerSumLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -135,7 +145,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.integerMultQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -147,7 +157,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.integerMultLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -164,7 +174,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.floatingSumQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -176,7 +186,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.floatingSumLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -193,7 +203,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.floatingMultQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -205,7 +215,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.floatingMultLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -222,7 +232,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.memoryQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -234,7 +244,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.memoryLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -251,7 +261,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MIN} max={SUPERSCALAR_CONFIG.FUNCTIONAL_UNIT_MAX} value={config.jumpQuantity} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -263,7 +273,7 @@ export const SuperscalarConfigModal: React.FC = ({ min={SUPERSCALAR_CONFIG.LATENCY_MIN} max={SUPERSCALAR_CONFIG.LATENCY_MAX} value={config.jumpLatency} - onChange={updateConfig} + onChange={updateNumConfig} /> @@ -275,33 +285,145 @@ export const SuperscalarConfigModal: React.FC = ({
-
{t("superscalarModal.parameters")}
- - -
- - - - - {t("superscalarModal.issue")} - - - - - - - -
- -
-
+
{t("superscalarModal.parameters")}
+ + +
+ + + + + + {t("superscalarModal.issue")} + + + + + + + + + + + + {t("superscalarModal.cacheType")} + + + + + + + + + + + + {config.cacheType !== CacheType.NO_CACHE && ( + + + + + {t("batchModal.cacheFaultLatency")} + + + + + + + + )} + {config.cacheType === CacheType.RANDOM_CACHE && ( + + + + + {t("batchModal.cacheFaultPercentage")} + + + + + + + + )} + {config.cacheType === CacheType.DIRECT_CACHE && ( + <> + + + + + {t("superscalarModal.cacheBlocks")} + + + + + + + + + + + + {t("superscalarModal.cacheLines")} + + + + + + + + + )} + +
+ +
+ @@ -316,6 +438,6 @@ export const SuperscalarConfigModal: React.FC = ({ }; export default connect( - mapStateToProps, - mapDispatchToProps, + mapStateToProps, + mapDispatchToProps, )(withTranslation()(SuperscalarConfigModal)); diff --git a/src/interface/components/VLIW/modal/BatchModalComponent.tsx b/src/interface/components/VLIW/modal/BatchModalComponent.tsx index ba10a923..6a93e00f 100644 --- a/src/interface/components/VLIW/modal/BatchModalComponent.tsx +++ b/src/interface/components/VLIW/modal/BatchModalComponent.tsx @@ -12,21 +12,11 @@ class BatchModalComponent extends React.Component { constructor(public props: any, public state: any) { super(props); this.state = { - replications: 10, - cacheFailPercentage: 30, - cacheFailLatency: 9 + replications: 10 }; this.close = this.close.bind(this); this.setOptions = this.setOptions.bind(this); this.handleChange = this.handleChange.bind(this); - this.handleCachePercentageChange = this.handleCachePercentageChange.bind( - this - ); - this.handleCacheFailLatencyChange = this.handleCacheFailLatencyChange.bind( - this - ); - - } close() { @@ -41,26 +31,11 @@ class BatchModalComponent extends React.Component { setOptions() { VLIWIntegration.setBatchMode( - this.state.replications, - this.state.cacheFailLatency, - this.state.cacheFailPercentage - ); + this.state.replications); this.close(); VLIWIntegration.makeBatchExecution(); } - handleCachePercentageChange(event) { - let newState = { ...this.state }; - newState.cacheFailPercentage = event.target.value; - this.setState(newState); - } - - handleCacheFailLatencyChange(event) { - let newState = { ...this.state }; - newState.cacheFailLatency = event.target.value; - this.setState(newState); - } - render() { return ( @@ -88,44 +63,6 @@ class BatchModalComponent extends React.Component { /> -
- -
- -
-
-
- -
- -
-
diff --git a/src/interface/components/VLIW/modal/VLIWConfigModalComponent.tsx b/src/interface/components/VLIW/modal/VLIWConfigModalComponent.tsx index 7c0d6eb7..d7b9ec96 100644 --- a/src/interface/components/VLIW/modal/VLIWConfigModalComponent.tsx +++ b/src/interface/components/VLIW/modal/VLIWConfigModalComponent.tsx @@ -1,280 +1,424 @@ -import * as React from 'react'; -import { Modal, Button } from 'react-bootstrap'; -import { withTranslation } from 'react-i18next'; -import { toggleVliwConfigModal } from '../../../actions/modals'; -import { bindActionCreators } from 'redux'; +import * as React from "react"; +import { + Alert, + Button, + Col, + Container, + Form, + Modal, + Row, + Stack, +} from "react-bootstrap"; +import { type WithTranslation, withTranslation } from "react-i18next"; +import { toggleVliwConfigModal } from "../../../actions/modals"; +import { type Dispatch, bindActionCreators, type UnknownAction } from "redux"; -import VLIWIntegration from '../../../../integration/vliw-integration'; -import { VLIW_CONFIG } from '../../../utils/constants'; +import VLIWIntegration from "../../../../integration/vliw-integration"; +import { BATCH_CONFIG, VLIW_CONFIG } from "../../../utils/constants"; -import { connect } from 'react-redux'; +import { connect } from "react-redux"; +import type { GlobalState } from "@/interface/reducers"; +import { CacheType } from "@/core/Common/Cache"; -class VliwConfigModalComponent extends React.Component { +const mapStateToProps = (state: GlobalState) => { + return { + isVliwConfigModalOpen: state.Ui.isVliwConfigModalOpen, + }; +}; - constructor(public props: any, public state: any) { - super(props); +const mapDispatchToProps = (dispatch: Dispatch) => { + return { actions: bindActionCreators({ toggleVliwConfigModal }, dispatch) }; +}; +export type VliwConfigModalProps = WithTranslation & + ReturnType & + ReturnType; - this.cancel = this.cancel.bind(this); - this.close = this.close.bind(this); - this.handleChange = this.handleChange.bind(this); - this.setDefault = this.setDefault.bind(this); - this.saveVliwConfig = this.saveVliwConfig.bind(this); +export const vliwConfigModal: React.FC = ({ + isVliwConfigModalOpen, + actions, + t, +}: VliwConfigModalProps) => { + const defaultConfig = { + integerSumQuantity: 2, + integerSumLatency: 1, + integerMultQuantity: 2, + integerMultLatency: 2, + floatingSumQuantity: 2, + floatingSumLatency: 4, + floatingMultQuantity: 2, + floatingMultLatency: 6, + memoryQuantity: 2, + memoryLatency: 4, + jumpQuantity: 1, + jumpLatency: 2, + issueGrade: 4, + cacheType: CacheType.NO_CACHE, + cacheFailPercentage: 30, + cacheFailLatency: 9, + cacheBlocks: 4, + cacheLines: 16, + }; - this.state = { - vliwConfig: { - integerSumQuantity: 2, - integerSumLatency: 1, - integerMultQuantity: 2, - integerMultLatency: 2, - floatingSumQuantity: 2, - floatingSumLatency: 4, - floatingMultQuantity: 2, - floatingMultLatency: 6, - memoryQuantity: 2, - memoryLatency: 4, - jumpQuantity: 1, - jumpLatency: 2, - } - }; - } + const [config, setConfig] = React.useState(defaultConfig); - saveVliwConfig() { - console.log(this.state.vliwConfig); - VLIWIntegration.saveVliwConfig(this.state.vliwConfig); - this.close(); - } + const saveConfig = () => { + VLIWIntegration.saveVliwConfig(config); + closeModal(); + }; - handleChange(event) { - let newState = Object.assign({}, this.state); - newState.vliwConfig[event.target.name] = event.target.value; - this.setState(newState); - } + const updateNumConfig = (event) => { + setConfig({ ...config, [event.target.name]: Number(event.target.value) }); + }; - cancel() { - this.setDefault(); - this.close(); - } + const updateStrConfig = (event) => { + setConfig({ ...config, [event.target.name]: event.target.value }); + }; - setDefault() { - this.setState({ - vliwConfig: { - integerSumQuantity: 2, - integerSumLatency: 1, - integerMultQuantity: 2, - integerMultLatency: 2, - floatingSumQuantity: 2, - floatingSumLatency: 4, - floatingMultQuantity: 2, - floatingMultLatency: 6, - memoryQuantity: 2, - memoryLatency: 4, - jumpQuantity: 1, - jumpLatency: 2, - } - }); - } + const setDefaultConfig = () => { + setConfig(defaultConfig); + }; - close() { - this.props.actions.toggleVliwConfigModal(false); - }; + const closeModal = () => { + actions.toggleVliwConfigModal(false); + }; - render() { - return ( - - - {this.props.t('vliwModal.name')} - - -
-
-
- -
-
- -
-
-
-
-
- {this.props.t('functionalUnits.intAdd')} -
-
- -
-
- -
-
-
-
-
-
- {this.props.t('functionalUnits.intMult')} -
-
- -
-
- -
-
-
-
-
-
- {this.props.t('functionalUnits.floatAdd')} -
-
- -
-
- -
-
-
-
-
-
- {this.props.t('functionalUnits.floatMult')} -
-
- -
-
- -
-
-
-
-
-
- {this.props.t('functionalUnits.memory')} -
-
- -
-
- -
-
-
-
-
-
- {this.props.t('functionalUnits.jump')} -
-
- -
-
-
-
-
- - - - - -
); - } -} + return ( + + + {t("vliwModal.name")} + + + + {t("vliwModal.warning")} + +
{t("superscalarModal.functionalUnits")}
+ + +
+ + + + {t("superscalarModal.quantity")} + + + {t("superscalarModal.latency")} + + + + + {t("functionalUnits.intAdd")} + + + + + + + + + + + + + + + {t("functionalUnits.intMult")} + + + + + + + + + + + + + + + {t("functionalUnits.floatAdd")} + + + + + + + + + + + + + + + {t("functionalUnits.floatMult")} + + + + + + + + + + + + + + + {t("functionalUnits.memory")} + + + + + + + + + + + + + + + {t("functionalUnits.jump")} + + + + + + + + + + + + + +
+ +
+
+
+ +
{t("superscalarModal.parameters")}
+ + +
+ + + + + + {t("superscalarModal.cacheType")} + + + + + + + + + + + + {config.cacheType !== CacheType.NO_CACHE && ( + + + + + {t("batchModal.cacheFaultLatency")} + + + + + + + + )} + {config.cacheType === CacheType.RANDOM_CACHE && ( + + + + + {t("batchModal.cacheFaultPercentage")} + + + + + + + + )} + {config.cacheType === CacheType.DIRECT_CACHE && ( + <> + + + + + {t("superscalarModal.cacheBlocks")} + + + + + + + + + + + + {t("superscalarModal.cacheLines")} + + + + + + + + + )} + +
+ +
+
+
+
+ + + + + +
+ ); +}; -const mapStateToProps = state => { - return { - isVliwConfigModalOpen: state.Ui.isVliwConfigModalOpen, - } -} - -function mapDispatchToProps(dispatch) { - return { actions: bindActionCreators({toggleVliwConfigModal}, dispatch)}; -} -export default connect(mapStateToProps, mapDispatchToProps)(withTranslation()(VliwConfigModalComponent)); +export default connect( + mapStateToProps, + mapDispatchToProps, +)(withTranslation()(vliwConfigModal)); diff --git a/src/interface/utils/constants.ts b/src/interface/utils/constants.ts index 5be3d21c..737cdb61 100644 --- a/src/interface/utils/constants.ts +++ b/src/interface/utils/constants.ts @@ -4,7 +4,11 @@ export const SUPERSCALAR_CONFIG = { LATENCY_MIN: 0, LATENCY_MAX: 100, ISSUE_GRADE_MIN: 1, - ISSUE_GRADE_MAX: 16 + ISSUE_GRADE_MAX: 16, + CACHE_BLOCKS_MIN: 1, + CACHE_BLOCKS_MAX: 100, + CACHE_LINES_MIN: 1, + CACHE_LINES_MAX: 1024 }; export const VLIW_CONFIG = { @@ -13,7 +17,11 @@ export const VLIW_CONFIG = { LATENCY_MIN: 0, LATENCY_MAX: 100, ISSUE_GRADE_MIN: 1, - ISSUE_GRADE_MAX: 16 + ISSUE_GRADE_MAX: 16, + CACHE_BLOCKS_MIN: 1, + CACHE_BLOCKS_MAX: 100, + CACHE_LINES_MIN: 1, + CACHE_LINES_MAX: 1024 }; export const BATCH_CONFIG = { diff --git a/src/test/functional/Superscalar/iteratelist.spec.ts b/src/test/functional/Superscalar/iteratelist.spec.ts index 2b1d40bf..f40f5ab5 100644 --- a/src/test/functional/Superscalar/iteratelist.spec.ts +++ b/src/test/functional/Superscalar/iteratelist.spec.ts @@ -22,7 +22,7 @@ test('recorrelista.pla is executed properly', t => { // Load memory const memContentBaseAddress = 10; for (let i = 0; i < memContent.length; i++) { - context.machine.memory.setDatum(memContentBaseAddress + i, memContent[i]); + context.machine.memory.setData(memContentBaseAddress + i, memContent[i]); } // Execute code @@ -68,6 +68,6 @@ test('recorrelista.pla is executed properly', t => { expect(context.machine.pc).toBe(19); // Check the result - expect(Array.from(context.machine.memory)[9].value).toBe(12); + expect(Array.from(context.machine.memory)[9]).toBe(12); }) \ No newline at end of file diff --git a/src/test/functional/Superscalar/loop.spec.ts b/src/test/functional/Superscalar/loop.spec.ts index 9eedf37a..62a997d8 100644 --- a/src/test/functional/Superscalar/loop.spec.ts +++ b/src/test/functional/Superscalar/loop.spec.ts @@ -21,10 +21,10 @@ test('Bucle.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -36,7 +36,7 @@ test('Bucle.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -49,10 +49,10 @@ test('Buclesoft.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -64,7 +64,7 @@ test('Buclesoft.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -77,10 +77,10 @@ test('Bucledoble.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -92,7 +92,7 @@ test('Bucledoble.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + 5 ); expect(result).toStrictEqual(resultContent.map(x => x * sumContent).slice(0, 5)); diff --git a/src/test/functional/Superscalar/speculativenosideeffects.spec.ts b/src/test/functional/Superscalar/speculativenosideeffects.spec.ts index 514e478d..4e36bd1b 100644 --- a/src/test/functional/Superscalar/speculativenosideeffects.spec.ts +++ b/src/test/functional/Superscalar/speculativenosideeffects.spec.ts @@ -23,7 +23,7 @@ test('Speculative execution has no side effects', t => { expect(context.machine.getGpr(5)).toBe(0); // Check memory pos 5 value - expect(Array.from(context.machine.memory)[5].value).toBe(0); + expect(Array.from(context.machine.memory)[5]).toBe(0); // Check F1 value expect(context.machine.getFpr(1)).toBe(0); diff --git a/src/test/functional/VLIW/loop.spec.ts b/src/test/functional/VLIW/loop.spec.ts index cdacb772..919c512d 100644 --- a/src/test/functional/VLIW/loop.spec.ts +++ b/src/test/functional/VLIW/loop.spec.ts @@ -27,10 +27,10 @@ test('Bucle.pla is executed properly', () => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -41,7 +41,7 @@ test('Bucle.pla is executed properly', () => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -58,10 +58,10 @@ test('Bucle2.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -73,7 +73,7 @@ test('Bucle2.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -90,10 +90,10 @@ test('Bucle3.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -105,7 +105,7 @@ test('Bucle3.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -122,10 +122,10 @@ test('Bucle4.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -137,7 +137,7 @@ test('Bucle4.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -154,10 +154,10 @@ test('Buclesoft.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -169,7 +169,7 @@ test('Buclesoft.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); @@ -186,10 +186,10 @@ test('Buclesoft2.pla is executed properly', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(40, sumContent); + context.machine.memory.setData(40, sumContent); const vecBaseAddress = 50; for (let i = 0; i < vecContent.length; i++) { - context.machine.memory.setDatum(vecBaseAddress + i, vecContent[i]); + context.machine.memory.setData(vecBaseAddress + i, vecContent[i]); } // Execute code @@ -201,7 +201,7 @@ test('Buclesoft2.pla is executed properly', t => { // Check the result const resultBaseAddress = 70; - const result = Array.from(context.machine.memory).map(d => d.value).slice( + const result = Array.from(context.machine.memory).slice( resultBaseAddress, resultBaseAddress + resultContent.length ); expect(result).toStrictEqual(resultContent); diff --git a/src/test/functional/VLIW/multiwayvliw.spec.ts b/src/test/functional/VLIW/multiwayvliw.spec.ts index 1e33c942..6fef5ff5 100644 --- a/src/test/functional/VLIW/multiwayvliw.spec.ts +++ b/src/test/functional/VLIW/multiwayvliw.spec.ts @@ -21,8 +21,8 @@ test('multiwayvliw.pla is executed properly with first parameter', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(10, 1.1); - context.machine.memory.setDatum(11, 2.2); + context.machine.memory.setData(10, 1.1); + context.machine.memory.setData(11, 2.2); context.machine.setGpr(32, 0); // Execute code @@ -32,7 +32,7 @@ test('multiwayvliw.pla is executed properly with first parameter', t => { expect(context.machine.pc).toBe(11); // Check the result - expect(Array.from(context.machine.memory)[12].value).toBe(1.1); + expect(Array.from(context.machine.memory)[12]).toBe(1.1); // Check the cycles // 6 + 5 + 1 + 3 (last inst latency) = 15 + 1 @@ -46,8 +46,8 @@ test('multiwayvliw.pla is executed properly with second parameter', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(10, 1.1); - context.machine.memory.setDatum(11, 2.2); + context.machine.memory.setData(10, 1.1); + context.machine.memory.setData(11, 2.2); context.machine.setGpr(32, 1); // Execute code @@ -57,7 +57,7 @@ test('multiwayvliw.pla is executed properly with second parameter', t => { expect(context.machine.pc).toBe(11); // Check the result - expect(Array.from(context.machine.memory)[12].value).toBe(2.2); + expect(Array.from(context.machine.memory)[12]).toBe(2.2); // Check the cycles // 6 + 5 + 1 + 3 (last inst latency) = 15 + 1 @@ -71,8 +71,8 @@ test('multiwayvliw.pla is executed properly with third parameter', t => { context.machine.code = context.code; // Load memory - context.machine.memory.setDatum(10, 1.1); - context.machine.memory.setDatum(11, 2.2); + context.machine.memory.setData(10, 1.1); + context.machine.memory.setData(11, 2.2); context.machine.setGpr(32, 2); // Execute code @@ -82,7 +82,7 @@ test('multiwayvliw.pla is executed properly with third parameter', t => { expect(context.machine.pc).toBe(11); // Check the result - expect(Array.from(context.machine.memory)[12].value).toBeCloseTo(3.3, 5); + expect(Array.from(context.machine.memory)[12]).toBeCloseTo(3.3, 5); // Check the cycles // 6 + 5 + 3 (last inst latency) = 14 + 1 diff --git a/src/test/unit/core/Common/Cache.spec.ts b/src/test/unit/core/Common/Cache.spec.ts new file mode 100644 index 00000000..f686fc06 --- /dev/null +++ b/src/test/unit/core/Common/Cache.spec.ts @@ -0,0 +1,118 @@ +import { expect, beforeEach, test } from "vitest"; +import { RandomCache, DirectCache } from "@/core/Common/Cache"; +import { Memory } from "@/core/Common/Memory"; + +let memory: Memory; + +beforeEach(() => { + memory = new Memory(100); +}); + +test("DirectCache doesn't alter memory writes", (t) => { + const directCache = new DirectCache(10, 100); + const randomPosition = Math.floor(Math.random() * 100); + + // proxy the memory + memory.getData = new Proxy(memory.getData, directCache.getHandler); + memory.setData = new Proxy(memory.setData, directCache.setHandler); + + // write to the memory + memory.setData(randomPosition, 10); + + expect(memory.getData(randomPosition)).toBe(10); + // now the cache sould have the writen block loaded, so the previus read should be successful + expect(directCache.success).toBe(true); +}); + +test("RandomCache faults the random percentage and returns the memory data", (t) => { + const randomCache = new RandomCache(0.5); + + // fill memory with random data + for (let i = 0; i < 100; i++) { + memory.setData(i, i); + } + + // proxy the memory + memory.getData = new Proxy(memory.getData, randomCache.getHandler); + memory.setData = new Proxy(memory.setData, randomCache.setHandler); + + // test reads 1000 times + let faults = 0; + for (let i = 0; i < 1000; i++) { + const randomPosition = Math.floor(Math.random() * 100); + const result = memory.getData(randomPosition); + if (result instanceof Error) { + throw result; + } + expect(result).toBe(memory.getData(randomPosition)); + if (!randomCache.success) { + faults++; + } + } + + // check that the faults are around 50%, with a margin of 10% + expect(faults).toBeGreaterThan(400); + expect(faults).toBeLessThan(600); +}); + +test("DirectCache with one big block the same length as memory never faults and returns the memory data", (t) => { + const directCache = new DirectCache(1, 100); + + // fill memory with random data + for (let i = 0; i < 100; i++) { + memory.setData(i, i); + } + + // proxy the memory + memory.getData = new Proxy(memory.getData, directCache.getHandler); + memory.setData = new Proxy(memory.setData, directCache.setHandler); + + // read one position, wich should fail, as the block is not in the cache + const randomPosition = Math.floor(Math.random() * 100); + expect(memory.getData(randomPosition)).toBe(randomPosition); + expect(directCache.success).toBe(false); + + // read all positions of memory + for (let i = 0; i < 100; i++) { + expect(memory.getData(i)).toBe(i); + expect(directCache.success).toBe(true); + } +}); + +test("DirectCache with as many blocks as positions should fail only on the first read", (t) => { + const directCache = new DirectCache(100, 100); + + // proxy the memory + memory.getData = new Proxy(memory.getData, directCache.getHandler); + memory.setData = new Proxy(memory.setData, directCache.setHandler); + + // read all positions of memory, all should fail + for (let i = 0; i < 100; i++) { + memory.getData(i); + expect(directCache.success).toBe(false); + } + + // read all positions of memory, all should succeed + for (let i = 0; i < 100; i++) { + memory.getData(i); + expect(directCache.success).toBe(true); + } +}); + +test("DirectCache should always fault on reading alternatively from blocks with the same position", (t) => { + // create a cache with one block and smaller than memory, so the first and last address will have a different block + const directCache = new DirectCache(1, 10); + + // proxy the memory + memory.getData = new Proxy(memory.getData, directCache.getHandler); + memory.setData = new Proxy(memory.setData, directCache.setHandler); + + // alternatively read from the first and last address + for (let i = 0; i < 10; i++) { + memory.getData(0); + expect(directCache.success).toBe(false); + + memory.getData(99); + expect(directCache.success).toBe(false); + } +});