-
Notifications
You must be signed in to change notification settings - Fork 268
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(avm): implement addressing modes for MOV (#4490)
Creates `Addressing` class to handle addressing modes. I might later change the instruction constructors to take/accept `Addressing`. Closes: #4266.
- Loading branch information
Showing
6 changed files
with
186 additions
and
54 deletions.
There are no files selected for viewing
49 changes: 49 additions & 0 deletions
49
yarn-project/simulator/src/avm/opcodes/addressing_mode.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { TaggedMemory, Uint32 } from '../avm_memory_types.js'; | ||
import { Addressing, AddressingMode } from './addressing_mode.js'; | ||
|
||
describe('Addressing', () => { | ||
it('should reserialize correctly', () => { | ||
const addressingMode = Addressing.fromWire(0b10101010); | ||
const wireModes = addressingMode.toWire(); | ||
expect(wireModes).toBe(0b10101010); | ||
}); | ||
|
||
it('should convert to wire format correctly', () => { | ||
const addressingMode = new Addressing([ | ||
AddressingMode.INDIRECT, | ||
AddressingMode.DIRECT, | ||
AddressingMode.INDIRECT, | ||
AddressingMode.DIRECT, | ||
]); | ||
const wireModes = addressingMode.toWire(); | ||
expect(wireModes).toBe(0b00000101); | ||
}); | ||
|
||
it('should convert from wire format correctly', () => { | ||
const addressingMode = Addressing.fromWire(0b00011001); | ||
const expected = new Addressing([ | ||
AddressingMode.INDIRECT, | ||
AddressingMode.DIRECT, | ||
AddressingMode.DIRECT, | ||
AddressingMode.INDIRECT, | ||
AddressingMode.INDIRECT, | ||
AddressingMode.DIRECT, | ||
AddressingMode.DIRECT, | ||
AddressingMode.DIRECT, | ||
]); | ||
|
||
expect(addressingMode).toStrictEqual(expected); | ||
}); | ||
|
||
it('should resolve offsets correctly', () => { | ||
const addressingMode = Addressing.fromWire(0b00011001); | ||
const offsets = [10, 20, 30]; | ||
const mem = new TaggedMemory(); | ||
mem.set(10, new Uint32(100)); | ||
mem.set(20, new Uint32(200)); | ||
mem.set(30, new Uint32(300)); | ||
|
||
const resolved = addressingMode.resolve(offsets, mem); | ||
expect(resolved).toEqual([100, 20, 30]); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
import { strict as assert } from 'assert'; | ||
|
||
import { TaggedMemory, TypeTag } from '../avm_memory_types.js'; | ||
|
||
export enum AddressingMode { | ||
DIRECT, | ||
INDIRECT, | ||
INDIRECT_PLUS_CONSTANT, // Not implemented yet. | ||
} | ||
|
||
/** A class to represent the addressing mode of an instruction. */ | ||
export class Addressing { | ||
public constructor( | ||
/** The addressing mode for each operand. The length of this array is the number of operands of the instruction. */ | ||
private readonly modePerOperand: AddressingMode[], | ||
) { | ||
assert(modePerOperand.length <= 8, 'At most 8 operands are supported'); | ||
} | ||
|
||
public static fromWire(wireModes: number): Addressing { | ||
// The modes are stored in the wire format as a byte, with each bit representing the mode for an operand. | ||
// The least significant bit represents the zeroth operand, and the most significant bit represents the last operand. | ||
const modes = new Array<AddressingMode>(8); | ||
for (let i = 0; i < 8; i++) { | ||
modes[i] = (wireModes & (1 << i)) === 0 ? AddressingMode.DIRECT : AddressingMode.INDIRECT; | ||
} | ||
return new Addressing(modes); | ||
} | ||
|
||
public toWire(): number { | ||
// The modes are stored in the wire format as a byte, with each bit representing the mode for an operand. | ||
// The least significant bit represents the zeroth operand, and the least significant bit represents the last operand. | ||
let wire: number = 0; | ||
for (let i = 0; i < 8; i++) { | ||
if (this.modePerOperand[i] === AddressingMode.INDIRECT) { | ||
wire |= 1 << i; | ||
} | ||
} | ||
return wire; | ||
} | ||
|
||
/** | ||
* Resolves the offsets using the addressing mode. | ||
* @param offsets The offsets to resolve. | ||
* @param mem The memory to use for resolution. | ||
* @returns The resolved offsets. The length of the returned array is the same as the length of the input array. | ||
*/ | ||
public resolve(offsets: number[], mem: TaggedMemory): number[] { | ||
assert(offsets.length <= this.modePerOperand.length); | ||
const resolved = new Array(offsets.length); | ||
for (const [i, offset] of offsets.entries()) { | ||
switch (this.modePerOperand[i]) { | ||
case AddressingMode.INDIRECT: | ||
mem.checkTag(TypeTag.UINT32, offset); | ||
resolved[i] = Number(mem.get(offset).toBigInt()); | ||
break; | ||
case AddressingMode.DIRECT: | ||
resolved[i] = offset; | ||
break; | ||
default: | ||
throw new Error(`Unimplemented addressing mode: ${AddressingMode[this.modePerOperand[i]]}`); | ||
} | ||
} | ||
return resolved; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.