Skip to content
Merged
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
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"files.watcherExclude": {
"**/.home": true
},
"asciidoc.antora.enableAntoraSupport": true
"asciidoc.antora.showEnableAntoraPrompt": true
}
64 changes: 57 additions & 7 deletions arch/csr/mstatus.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,29 @@ mstatus:

Read-only bit that summarizes whether either the FS, XS, or VS
fields signal the presence of some dirty state.
type: RO-H
reset_value: UNDEFINED_LEGAL
affectedBy: [F, D, V]
definedBy:
anyOf: [F,V] # NOTE: if you implement a custom extension overlay that writes to XS, then you need to add your extension here in the overlay as well
type(): |
# this is read-only if FS and VS are both read-only
# otherwise, it is read-only with hardware update

if (implemented?(ExtensionName::F) && (HW_MSTATUS_FS_DIRTY_UPDATE != "never")) {
return CsrFieldType::ROH;
} else if (implemented?(ExtensionName::V) && (HW_MSTATUS_VS_DIRTY_UPDATE != "never")) {
return CsrFieldType::ROH;
} else {
return CsrFieldType::RO;
}
reset_value(): |
# the reset value is known if both FS and VS are legal
# make this a function call so that it can be displayed succinctly in docs

if (mstatus_sd_has_known_reset()) {
return mstatus_sd_reset_value();
} else {
return UNDEFINED_LEGAL;
}

MPV:
location: 39
base: 64
Expand Down Expand Up @@ -339,7 +359,8 @@ mstatus:
# there will be no hardware update in this case because we know the F extension isn't implemented
return MSTATUS_FS_WRITEABLE ? CsrFieldType::RW : CsrFieldType::RO;
}
definedBy: F
definedBy:
anyOf: [F, S]
reset_value(): |
if (CSR[misa].F == 1'b1){
return UNDEFINED_LEGAL;
Expand Down Expand Up @@ -410,9 +431,38 @@ mstatus:
When a vector register or vector CSR is written, VS obtains the value 3.
Values 1 and 2 are valid write values for software, but are not interpreted by hardware
other than to possibly enable a previously-disabled vector unit.
type: RW-H
reset_value: UNDEFINED_LEGAL
definedBy: V
definedBy:
anyOf: [V, S]
type(): |
if (CSR[misa].V == 1'b1){
return CsrFieldType::RWH;
} else if ((CSR[misa].S == 1'b0) && (CSR[misa].V == 1'b0)) {
# must be read-only-0
return CsrFieldType::RO;
} else {
# there will be no hardware update in this case because we know the V extension isn't implemented
return MSTATUS_VS_WRITEABLE ? CsrFieldType::RW : CsrFieldType::RO;
}
reset_value(): |
if (CSR[misa].V == 1'b1){
return UNDEFINED_LEGAL;
} else if ((CSR[misa].S == 1'b0) && (CSR[misa].V == 1'b0)) {
# must be read-only-0
return 0;
} else {
# there will be no hardware update in this case because we know the V extension isn't implemented
return MSTATUS_VS_WRITEABLE ? UNDEFINED_LEGAL : 0;
}
sw_write(csr_value): |
if (CSR[misa].V == 1'b1){
return ary_includes?<$array_size(MSTATUS_VS_LEGAL_VALUES), 2>(MSTATUS_VS_LEGAL_VALUES, csr_value.FS) ? csr_value.FS : UNDEFINED_LEGAL_DETERMINISTIC;
} else if ((CSR[misa].S == 1'b0) && (CSR[misa].V == 1'b0)) {
# must be read-only-0
return 0;
} else {
# there will be no hardware update in this case because we know the V extension isn't implemented
return ary_includes?<$array_size(MSTATUS_VS_LEGAL_VALUES), 2>(MSTATUS_VS_LEGAL_VALUES, csr_value.FS) ? csr_value.FS : UNDEFINED_LEGAL_DETERMINISTIC;
}
SPP:
location: 8
description: |
Expand Down
6 changes: 3 additions & 3 deletions arch/ext/F.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -246,13 +246,13 @@ F:
Values are:
[separator="!"]
!===
h! none ! Hardware never writes `mstatus.FS`
h! never ! Hardware never writes `mstatus.FS`
h! precise ! Hardware writes `mstatus.FS` to the Dirty (3) state precisely when F registers are modified
h! imprecise ! Hardware writes `mstatus.FS` imprecisely. This will result in a call to unpredictable() on any attempt to read `mstatus` or write FP state.
!===
schema:
type: string
enum: ["none", "precise", "imprecise"]
enum: ["never", "precise", "imprecise"]
MSTATUS_FS_LEGAL_VALUES:
description: |
The set of values that mstatus.FS will accept from a software write.
Expand All @@ -268,4 +268,4 @@ F:
assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F)

# if HW is writing FS, then Dirty (3) better be a supported value
assert MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) && (HW_MSTATUS_FS_DIRTY_UPDATE != "none")
assert MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F) && (HW_MSTATUS_FS_DIRTY_UPDATE != "never")
25 changes: 25 additions & 0 deletions arch/ext/S.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -254,6 +254,15 @@ S:
type: boolean
extra_validation:
assert MSTATUS_FS_WRITEABLE == true if ext?(:F)
MSTATUS_VS_WRITEABLE:
description: |
When `S` is enabled but `V` is not, mstatus.VS is optionally writeable.

This parameter only has an effect when both S and V mode are disabled.
schema:
type: boolean
extra_validation:
assert MSTATUS_VS_WRITEABLE == true if ext?(:V)
MSTATUS_FS_LEGAL_VALUES:
description: |
The set of values that mstatus.FS will accept from a software write.
Expand All @@ -267,6 +276,22 @@ S:
also_defined_in: F
extra_validation: |
assert MSTATUS_FS_LEGAL_VALUES.include?(0) && MSTATUS_FS_LEGAL_VALUES.include?(3) if ext?(:F)
MSTATUS_VS_LEGAL_VALUES:
description: |
The set of values that mstatus.VS will accept from a software write.
schema:
type: array
items:
type: integer
enum: [0,1,2,3]
maxItems: 4
uniqueItems: true
also_defined_in: V
extra_validation: |
assert MSTATUS_VS_LEGAL_VALUES.include?(0) && MSTATUS_VS_LEGAL_VALUES.include?(3) if ext?(:V)

# if HW is writing VS, then Dirty (3) better be a supported value
assert MSTATUS_VS_LEGAL_VALUES.include?(3) if ext?(:V) && (HW_MSTATUS_VS_DIRTY_UPDATE != "never")
MSTATUS_TVM_IMPLEMENTED:
description: |
Whether or not mstatus.TVM is implemented.
Expand Down
32 changes: 31 additions & 1 deletion arch/ext/V.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,34 @@ V:
description: |
Indicates whether or not the `V` extension can be disabled with the `misa.V` bit.
schema:
type: boolean
type: boolean
HW_MSTATUS_VS_DIRTY_UPDATE:
description: |
Indicates whether or not hardware will write to `mstatus.VS`

Values are:
[separator="!"]
!===
h! never ! Hardware never writes `mstatus.VS`
h! precise ! Hardware writes `mstatus.VS` to the Dirty (3) state precisely when V registers are modified
h! imprecise ! Hardware writes `mstatus.VS` imprecisely. This will result in a call to unpredictable() on any attempt to read `mstatus` or write vector state.
!===
schema:
type: string
enum: ["never", "precise", "imprecise"]
MSTATUS_VS_LEGAL_VALUES:
description: |
The set of values that mstatus.VS will accept from a software write.
schema:
type: array
items:
type: integer
enum: [0,1,2,3]
maxItems: 4
uniqueItems: true
also_defined_in: S
extra_validation: |
assert MSTATUS_VS_LEGAL_VALUES.include?(0) && MSTATUS_VS_LEGAL_VALUES.include?(3) if ext?(:V)

# if HW is writing VS, then Dirty (3) better be a supported value
assert MSTATUS_VS_LEGAL_VALUES.include?(3) if ext?(:V) && (HW_MSTATUS_VS_DIRTY_UPDATE != "never")
42 changes: 42 additions & 0 deletions arch/isa/globals.isa
Original file line number Diff line number Diff line change
Expand Up @@ -2798,3 +2798,45 @@ function write_memory {
}
}

function mstatus_sd_has_known_reset
{
returns Boolean
description {
Returns true if the mstatus.SD bit has a defined reset value, as determined by various parameters.
}
body {
# the reset value is known if both FS and VS are known

Boolean fs_has_single_value =
((!implemented?(ExtensionName::F)) || ($array_size(MSTATUS_FS_LEGAL_VALUES) == 1));

Boolean vs_has_single_value =
((!implemented?(ExtensionName::V)) || ($array_size(MSTATUS_VS_LEGAL_VALUES) == 1));

return fs_has_single_value && vs_has_single_value;
}
}

function mstatus_sd_reset_value
{
returns Bits<1>
description {
Returns the reset value of mstatus.SD when known
}
body {
# the reset value is known if both FS and VS are known
assert(mstatus_sd_has_known_reset(),
"mstatus_sd_reset_value is only defined when mstatus_sd_has_known_reset() == true");

Bits<2> fs_value, vs_value; # defaults to 0

if ((!implemented?(ExtensionName::F)) || ($array_size(MSTATUS_FS_LEGAL_VALUES) == 1)) {
fs_value = (!implemented?(ExtensionName::F)) ? 0 : MSTATUS_FS_LEGAL_VALUES[0];
}
if ((!implemented?(ExtensionName::V)) || ($array_size(MSTATUS_VS_LEGAL_VALUES) == 1)) {
fs_value = (!implemented?(ExtensionName::V)) ? 0 : MSTATUS_VS_LEGAL_VALUES[0];
}

return ((fs_value == 3) || (vs_value == 3)) ? 1 : 0;
}
}
3 changes: 3 additions & 0 deletions cfgs/generic_rv64/params.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -514,4 +514,7 @@ params:
MSTATUS_FS_WRITEABLE: true
MSTATUS_TVM_IMPLEMENTED: true
HW_MSTATUS_FS_DIRTY_UPDATE: precise
MSTATUS_VS_WRITEABLE: true
MSTATUS_VS_LEGAL_VALUES: [0,1,2,3]
HW_MSTATUS_VS_DIRTY_UPDATE: precise
FORCE_UPGRADE_CBO_INVAL_TO_FLUSH: true
35 changes: 29 additions & 6 deletions lib/idl/ast.rb
Original file line number Diff line number Diff line change
Expand Up @@ -361,6 +361,8 @@ def print_ast(indent = 0, indent_size: 2, io: $stdout)

# @!macro freeze_tree
def freeze_tree(global_symtab)
return if frozen?

@children.each { |child| child.freeze_tree(global_symtab) }
freeze
end
Expand Down Expand Up @@ -1095,6 +1097,8 @@ def initialize(input, interval, user_type)
end

def freeze_tree(global_symtab)
return if frozen?

# call type to get it set before we freeze the object
type(global_symtab)
freeze
Expand Down Expand Up @@ -1257,6 +1261,8 @@ def initialize(input, interval, name, size, fields)

# @!macro freeze_tree
def freeze_tree(global_symtab)
return if frozen?

type(global_symtab)
freeze
end
Expand Down Expand Up @@ -1498,7 +1504,9 @@ def type_check(symtab)
if var.type(symtab).kind == :array
value_result = value_try do
index_value = index.value(symtab)
type_error "Array index out of range" if index_value >= var.type(symtab).width
if var.type(symtab).width != :unknown
type_error "Array index out of range" if index_value >= var.type(symtab).width
end
end # Ok, doesn't need to be known

elsif var.type(symtab).integral?
Expand Down Expand Up @@ -2161,22 +2169,26 @@ def to_ast
class MultiVariableDeclarationAst < AstNode
include Declaration

# @return [AstNode] Declared type
def type_name = @children[0]
def var_names = @children[1..]

# @return [Array<AstNode>] Variable names
def var_name_nodes = @children[1..]

def initialize(input, interval, type_name, var_names)
super(input, interval, [type_name] + var_names)

@global = false
end

# mark this declaration as being in global scope
def make_global
@global = true
end

# @return [Array<String>] Variables being declared
def var_names
var_names.map(&:text_value)
var_name_nodes.map(&:text_value)
end

# @!macro type_check
Expand All @@ -2186,6 +2198,7 @@ def type_check(symtab)
add_symbol(symtab)
end

# @!macro type
def type(symtab)
if @global
type_name.type(symtab).clone.make_global
Expand All @@ -2196,13 +2209,13 @@ def type(symtab)

# @!macro add_symbol
def add_symbol(symtab)
var_names.each do |vname|
symtab.add(vname.text_values, Var.new(vname.text_value, type(symtab), type(symtab).default))
var_name_nodes.each do |vname|
symtab.add(vname.text_value, Var.new(vname.text_value, type(symtab), type(symtab).default))
end
end

# @!macro to_idl
def to_idl = "#{type_name.to_idl} #{var_names.map(&:to_idl).join(', ')}"
def to_idl = "#{type_name.to_idl} #{var_name_nodes.map(&:to_idl).join(', ')}"
end

class VariableDeclarationSyntaxNode < Treetop::Runtime::SyntaxNode
Expand Down Expand Up @@ -3415,6 +3428,8 @@ def initialize(input, interval, class_name, member_name)

# @!macro freeze_tree
def freeze_tree(global_symtab)
return if frozen?

enum_def_ast = global_symtab.archdef.global_ast.enums.find { |e| e.name == @enum_class_name }

@enum_def_type =
Expand Down Expand Up @@ -4179,6 +4194,8 @@ def type_check(symtab)
end

def freeze_tree(symtab)
return if frozen?

if @type_name == "Bits"
# precalculate size if possible
begin
Expand Down Expand Up @@ -4849,6 +4866,8 @@ def initialize(input, interval, name, targs, return_types, arguments, desc, body

# @!macro freeze_tree
def freeze_tree(global_symtab)
return if frozen?

unless templated?
arguments(global_symtab)
end
Expand Down Expand Up @@ -5679,6 +5698,8 @@ def initialize(input, interval, idx, field_name)
end

def freeze_tree(symtab)
return if frozen?

value_result = value_try do
@value = calc_value(symtab)
end
Expand Down Expand Up @@ -5819,6 +5840,8 @@ def initialize(input, interval, idx)
end

def freeze_tree(symtab)
return if frozen?

@archdef = symtab.archdef # remember archdef, used by gen_adoc pass
@idx.freeze_tree(symtab)
freeze
Expand Down
6 changes: 6 additions & 0 deletions lib/idl/passes/gen_adoc.rb
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,12 @@ def gen_adoc(indent = 0, indent_spaces: 2)
end
end

class MultiVariableDeclarationAst
def gen_adoc(indent = 0, indent_spaces: 2)
"#{' ' * indent}#{type_name.gen_adoc(0, indent_spaces:)} #{var_name_nodes.map { |var| var.gen_adoc(0, indent_spaces:) }.join(', ')}"
end
end

class TernaryOperatorExpressionAst
def gen_adoc(indent = 0, indent_spaces: 2)
"#{' ' * indent}#{condition.gen_adoc(0, indent_spaces:)} ? #{true_expression.gen_adoc(0, indent_spaces:)} : #{false_expression.gen_adoc(0, indent_spaces:)}"
Expand Down
Loading
Loading