diff --git a/backends/cpp_hart_gen/lib/gen_cpp.rb b/backends/cpp_hart_gen/lib/gen_cpp.rb index 9fb62c6b7..dd2ba3569 100644 --- a/backends/cpp_hart_gen/lib/gen_cpp.rb +++ b/backends/cpp_hart_gen/lib/gen_cpp.rb @@ -270,6 +270,8 @@ def gen_cpp(symtab, indent = 2, indent_spaces: 2) if csr_obj.nil? if function_name == "sw_read" "#{' ' * indent}__UDB_CSR_BY_ADDR(#{csr.idx_expr.gen_cpp(symtab, 0, indent_spaces:)}).#{function_name}(__UDB_XLEN)" + elsif function_name == "address" + "#{' ' * indent}__UDB_CSR_BY_ADDR(#{csr.idx_expr.gen_cpp(symtab, 0, indent_spaces:)}).address_bits()" else "#{' ' * indent}__UDB_CSR_BY_ADDR(#{csr.idx_expr.gen_cpp(symtab, 0, indent_spaces:)}).#{function_name.gsub('?', '_Q_')}(#{args_cpp.join(', ')})" end @@ -280,6 +282,8 @@ def gen_cpp(symtab, indent = 2, indent_spaces: 2) else "#{' ' * indent}__UDB_CSR_BY_NAME(#{csr_obj.name})._#{function_name}()" end + elsif function_name == "address" + "#{' ' * indent}__UDB_CSR_BY_NAME(#{csr_obj.name})._#{function_name}()" else "#{' ' * indent}__UDB_CSR_BY_NAME(#{csr_obj.name}).#{function_name.gsub('?', '_Q_')}(#{args_cpp.join(', ')})" end diff --git a/backends/cpp_hart_gen/templates/csrs.hxx.erb b/backends/cpp_hart_gen/templates/csrs.hxx.erb index 61f05f03c..76361ec86 100644 --- a/backends/cpp_hart_gen/templates/csrs.hxx.erb +++ b/backends/cpp_hart_gen/templates/csrs.hxx.erb @@ -207,9 +207,12 @@ namespace udb { CsrAddressType address_type() const override { return <%= csr.indirect? ? 'CsrAddressType::Indirect' : 'CsrAddressType::Direct' -%>; } unsigned address() const override { <%= !csr.indirect? ? "return #{csr.address};" : "throw CsrAddressTypeError(\"#{csr.name} is not direct addressible.\")" %>; } + _Bits<12, false> address_bits() const { <%= !csr.indirect? ? "return #{csr.address}_b;" : "throw CsrAddressTypeError(\"#{csr.name} is not direct addressible.\")" %>; } uint64_t indirect_address() const override { <%= csr.indirect? ? "return #{csr.indirect_address};" : "throw CsrAddressTypeError(\"#{csr.name} is not indirect.\")" %>; } uint8_t indirect_slot() const override { <%= csr.indirect? ? "return #{csr.indirect_slot};" : "throw CsrAddressTypeError(\"#{csr.name} is not indirect.\")" %>; } - static constexpr unsigned _address() { return <%= csr.address %>; } + <%- if !csr.indirect? -%> + static constexpr _Bits<12, false> _address() { return <%= csr.address %>_b; } + <%- end -%> const std::string name() const override { return "<%= csr.name %>"; } PrivilegeMode mode() const override { return PrivilegeMode::<%= csr.priv_mode %>; } bool writable() const override { return <%= csr.writable %>; } diff --git a/backends/instructions_appendix/all_instructions.golden.adoc b/backends/instructions_appendix/all_instructions.golden.adoc index 347714277..1451a2a6d 100644 --- a/backends/instructions_appendix/all_instructions.golden.adoc +++ b/backends/instructions_appendix/all_instructions.golden.adoc @@ -6310,6 +6310,78 @@ Included in:: |=== +[#udb:doc:inst:cm_jalt] +== cm.jalt + +Synopsis:: +Jump Via Table with Optional Link + +Assembly:: +cm.jalt index + +Encoding:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":8,"name": "index != {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31}","type":4},{"bits":6,"name": 0x28,"type":2}]} +.... + +Description:: +Read an address from the Jump Vector Table and jump to it, linking to `ra`. + + +Decode Variables:: +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|index |$encoding[9:2] +|=== + +Included in:: +[options="autowrap,autowidth"] +|=== +| Extension | Version + +| *Zcmt* | ~> 1.0.0 + +|=== + + +[#udb:doc:inst:cm_jt] +== cm.jt + +Synopsis:: +Jump Via Table + +Assembly:: +cm.jt index + +Encoding:: +[wavedrom, ,svg,subs='attributes',width="100%"] +.... +{"reg":[{"bits":2,"name": 0x2,"type":2},{"bits":5,"name": "index","type":4},{"bits":9,"name": 0x140,"type":2}]} +.... + +Description:: +Read an address from the Jump Vector Table and jump to it. + + +Decode Variables:: +[width="100%", cols="1,2", options="header"] +|=== +|Variable Name |Location +|index |$encoding[6:2] +|=== + +Included in:: +[options="autowrap,autowidth"] +|=== +| Extension | Version + +| *Zcmt* | ~> 1.0.0 + +|=== + + [#udb:doc:inst:cm_mva01s] == cm.mva01s diff --git a/spec/std/isa/inst/Zcmt/cm.jalt.yaml b/spec/std/isa/inst/Zcmt/cm.jalt.yaml new file mode 100644 index 000000000..3330e56ce --- /dev/null +++ b/spec/std/isa/inst/Zcmt/cm.jalt.yaml @@ -0,0 +1,64 @@ +# Copyright (c) Ventana Micro Systems +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.jalt +long_name: Jump Via Table with Optional Link +description: | + Read an address from the Jump Vector Table and jump to it, linking to `ra`. +definedBy: Zcmt +assembly: index +encoding: + match: 101000--------10 + variables: + - name: index + location: 9-2 + # prettier-ignore + not: [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31 ] +access: + s: always + u: always + vs: always + vu: always +operation(): | + # Ensure JVT readable + Csr csr_handle = direct_csr_lookup($bits(CSR[jvt].address())); + XReg jvt = csr_sw_read(csr_handle); + + if (CSR[jvt].MODE != 0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + # Skip over _this_ 16-bit instruction + XReg return_addr = $pc + 2; + X[1] = return_addr; + + XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; + XReg virtual_address = jump_table_base + index `* (xlen() / 8); + XReg addr; + TranslationResult result; + + # TODO: Correct this check when we figure out what MISA can do + if (CSR[misa].S == 1) { + result = translate(virtual_address, MemoryOperation::Fetch, mode(), $encoding); + } else { + result.paddr = virtual_address; + } + + # may raise an exception + access_check(result.paddr, xlen(), $pc, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); + + if (xlen() == 32) { + addr = read_physical_memory<32>(result.paddr); + } else { + addr = read_physical_memory<64>(result.paddr); + } # Ensure low-order bit is clear + + addr = addr & $signed(2'b10); + + jump(addr); + +sail(): | diff --git a/spec/std/isa/inst/Zcmt/cm.jt.yaml b/spec/std/isa/inst/Zcmt/cm.jt.yaml new file mode 100644 index 000000000..2ff6d9cf3 --- /dev/null +++ b/spec/std/isa/inst/Zcmt/cm.jt.yaml @@ -0,0 +1,59 @@ +# Copyright (c) Ventana Micro Systems +# SPDX-License-Identifier: BSD-3-Clause-Clear + +# yaml-language-server: $schema=../../../../schemas/inst_schema.json + +$schema: "inst_schema.json#" +kind: instruction +name: cm.jt +long_name: Jump Via Table +description: | + Read an address from the Jump Vector Table and jump to it. +definedBy: Zcmt +assembly: index +encoding: + match: 101000000-----10 + variables: + - name: index + location: 6-2 +access: + s: always + u: always + vs: always + vu: always +operation(): | + # Ensure JVT readable + Csr csr_handle = direct_csr_lookup(CSR[jvt].address()); + XReg jvt = csr_sw_read(csr_handle); + + if (CSR[jvt].MODE != 0) { + raise(ExceptionCode::IllegalInstruction, mode(), $encoding); + } + + XReg jump_table_base = { CSR[jvt].BASE, 6'b000000 }; + XReg virtual_address = jump_table_base + index `* (xlen() / 8); + XReg addr; + TranslationResult result; + + # TODO: Correct this check when we figure out what MISA can do + if (CSR[misa].S == 1) { + result = translate(virtual_address, MemoryOperation::Fetch, mode(), $encoding); + } else { + result.paddr = virtual_address; + } + + # may raise an exception + access_check(result.paddr, xlen(), $pc, MemoryOperation::Fetch, ExceptionCode::InstructionAccessFault, mode()); + + if (xlen() == 32) { + addr = read_physical_memory<32>(result.paddr); + } else { + addr = read_physical_memory<64>(result.paddr); + } + + # Ensure low-order bit is clear + addr = addr & $signed(2'b10); + + jump(addr); + +sail(): | diff --git a/tools/ruby-gems/idlc/lib/idlc/ast.rb b/tools/ruby-gems/idlc/lib/idlc/ast.rb index ea179764b..f82901015 100644 --- a/tools/ruby-gems/idlc/lib/idlc/ast.rb +++ b/tools/ruby-gems/idlc/lib/idlc/ast.rb @@ -2463,7 +2463,7 @@ def type(symtab) if symtab.mxlen == 64 && symtab.multi_xlen? Type.new(:bits, width: [field(symtab).location(32).size, field(symtab).location(64).size].max) else - Type.new(:bits, width: field(symtab).location(symtab.mxlen).size) + Type.new(:bits, width: field(symtab).location(symtab.mxlen.nil? ? 64 : symtab.mxlen).size) end elsif field(symtab).base64_only? Type.new(:bits, width: field(symtab).location(64).size) @@ -7445,8 +7445,11 @@ def initialize(input, interval, function_name, csr, args) def type_check(symtab) csr.type_check(symtab) - if ["sw_read", "address"].include?(function_name) + if function_name == "sw_read" type_error "unexpected argument(s)" unless args.empty? + elsif function_name == "address" + type_error "unexpected argument(s)" unless args.empty? + type_error "csr is accessed indirectly, and has no address" if csr_def(symtab)&.indirect? elsif ["implemented_without?"].include?(function_name) type_error "Expecting one argument" unless args.size == 1 type_error "Expecting an ExtensionName" unless args[0].type(symtab).kind == :enum_ref && args[0].class_name == "ExtensionName" diff --git a/tools/ruby-gems/idlc/lib/idlc/idl.treetop b/tools/ruby-gems/idlc/lib/idlc/idl.treetop index 63fb53843..83fd0b77f 100644 --- a/tools/ruby-gems/idlc/lib/idlc/idl.treetop +++ b/tools/ruby-gems/idlc/lib/idlc/idl.treetop @@ -331,11 +331,9 @@ grammar Idl rule bits_cast '$bits' space* '(' space* expr:( - csr_register_access_expression - / - enum_ref - / expression + / + csr_register_access_expression ) space* ')' end