Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
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
8 changes: 8 additions & 0 deletions doc/data-templates.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,9 @@ access:
vs: always # VS-mode access
vu: always # VU-mode access
data_independent_timing: true # For cryptographic extensions
pc: # program counter
references: true # Optional: instruction semantics reference the current PC
changes: false # Optional: instruction semantics update the PC
Comment on lines +101 to +102
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Subjective, but these might be better as read/write:

Suggested change
references: true # Optional: instruction semantics reference the current PC
changes: false # Optional: instruction semantics update the PC
reads: true # Optional: instruction semantics reference the PC
writes: false # Optional: instruction semantics update the PC

If adopted here, these changes would be needed throughout this PR, of course.

operation(): |
# IDL code implementing the instruction
X[xd] = X[xs1] + $signed(imm);
Expand All @@ -110,6 +113,11 @@ Common variable properties:
* `sign_extend` - Set to `true` for signed immediates
* `left_shift` - Shift value left by N bits (common for branch offsets)

Optional instruction metadata:

* `pc.references` - Set to `true` when the instruction semantics explicitly reference the current PC
* `pc.changes` - Set to `true` when the instruction semantics explicitly update the PC

=== Pseudoinstructions

Instructions can define pseudoinstruction mappings:
Expand Down
17 changes: 17 additions & 0 deletions spec/schemas/inst_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,23 @@
"description": "Whether or not the instruction must execute with data-independent timing when the Zkt extension is supported",
"default": false
},
"pc": {
"type": "object",
"description": "Whether the instruction reads and/or writes the program counter",
"properties": {
"references": {
"type": "boolean",
"default": false,
"description": "Whether the instruction semantics reference the current program counter"
},
"changes": {
"type": "boolean",
"default": false,
"description": "Whether the instruction semantics update the program counter"
}
},
"additionalProperties": false
},
"pseudoinstructions": {
"description": "Variations of this instruction that form a pseudoinstruction",
"type": "array",
Expand Down
2 changes: 2 additions & 0 deletions spec/std/isa/inst/I/auipc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,6 @@ access:
vs: always
vu: always
data_independent_timing: true
pc:
references: true
operation(): X[xd] = $pc + $signed(imm);
3 changes: 3 additions & 0 deletions spec/std/isa/inst/I/jalr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@ access:
u: always
vs: always
vu: always
pc:
references: true
changes: true
pseudoinstructions:
- when: xd == 0
to: jr imm(xs1)
Expand Down
2 changes: 2 additions & 0 deletions spec/std/isa/inst/I/mret.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ access:
u: never
vs: never
vu: never
pc:
changes: true
encoding:
match: "00110000001000000000000001110011"
operation(): |
Expand Down
6 changes: 6 additions & 0 deletions tools/ruby-gems/udb/lib/udb/obj/instruction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,12 @@ def base
# @return [Boolean] Whether or not the instruction must have data-independent timing when Zkt is enabled.
def data_independent_timing? = @data["data_independent_timing"]

# @return [Boolean] Whether or not the instruction semantics reference the current PC.
def pc_references? = @data.dig("pc", "references") || false

# @return [Boolean] Whether or not the instruction semantics update the PC.
def pc_changes? = @data.dig("pc", "changes") || false

# @param xlen [Integer] 32 or 64, the target xlen
# @return [Boolean] whethen or not instruction is defined in base +xlen+
def defined_in_base?(xlen)
Expand Down
53 changes: 53 additions & 0 deletions tools/ruby-gems/udb/test/test_instruction.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,18 @@
class TestInstruction < Minitest::Test
include Udb

private def operation_text(inst)
inst.instance_variable_get(:@data)["operation()"]
end

private def idl_references_pc?(operation)
operation.include?("$pc")
end

private def idl_changes_pc?(operation)
operation.match?(/(?:jump(?:_halfword)?\(|^\s*\$pc\s*=)/)
end

def setup
@resolver = Udb::Resolver.new(Udb.repo_root)
@cfg_arch = @resolver.cfg_arch_for("_")
Expand Down Expand Up @@ -61,4 +73,45 @@ def test_decode_variable_without_sext
extracted = rs1_var.extract
refute_match(/sext/, extracted, "non-signed decode variable should not use sext")
end

def test_explicit_pc_metadata
db = @cfg_arch

auipc_inst = db.instructions.find { |i| i.name == "auipc" }
refute_nil auipc_inst, "AUIPC instruction should be found"
assert auipc_inst.pc_references?, "AUIPC should explicitly reference the PC"
refute auipc_inst.pc_changes?, "AUIPC should not explicitly change the PC"

jalr_inst = db.instructions.find { |i| i.name == "jalr" }
refute_nil jalr_inst, "JALR instruction should be found"
assert jalr_inst.pc_references?, "JALR should explicitly reference the PC"
assert jalr_inst.pc_changes?, "JALR should explicitly change the PC"

mret_inst = db.instructions.find { |i| i.name == "mret" }
refute_nil mret_inst, "MRET instruction should be found"
refute mret_inst.pc_references?, "MRET should not explicitly reference the current PC"
assert mret_inst.pc_changes?, "MRET should explicitly change the PC"

add_inst = db.instructions.find { |i| i.name == "add" }
refute_nil add_inst, "ADD instruction should be found"
refute add_inst.pc_references?, "Instructions without pc metadata should default to not referencing the PC"
refute add_inst.pc_changes?, "Instructions without pc metadata should default to not changing the PC"
end

def test_explicit_pc_metadata_agrees_with_idl
@cfg_arch.instructions.each do |inst|
next unless inst.pc_references? || inst.pc_changes?

operation = operation_text(inst)
refute_nil operation, "#{inst.name} should define operation() when explicit pc metadata is present"

if inst.pc_references?
assert idl_references_pc?(operation), "#{inst.name} pc.references should agree with operation()"
end

if inst.pc_changes?
assert idl_changes_pc?(operation), "#{inst.name} pc.changes should agree with operation()"
end
end
end
end
Loading