diff --git a/.gitmodules b/.gitmodules index 642814f2..65bfb224 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "ext/riscv-opcodes"] path = ext/riscv-opcodes url = https://github.com/riscv/riscv-opcodes.git +[submodule "ext/docs-resources"] + path = ext/docs-resources + url = https://github.com/riscv/docs-resources.git diff --git a/Gemfile b/Gemfile index 6243d052..4866eeac 100644 --- a/Gemfile +++ b/Gemfile @@ -5,14 +5,14 @@ ruby "3.2.3" source "https://rubygems.org" gem "asciidoctor-diagram", "~> 2.2" -gem "asciidoctor-multipage" gem "asciidoctor-pdf" gem "base64" gem "bigdecimal" gem "json_schemer", "~> 1.0" gem "minitest" +gem "pygments.rb" gem "rake", "~> 13.0" -gem "slim", "~> 5.1" +gem "rouge" gem "treetop", "1.6.12" gem "webrick" gem "yard" diff --git a/Gemfile.lock b/Gemfile.lock index 00eac25c..b8c27847 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -15,8 +15,6 @@ GEM asciidoctor-diagram-ditaamini (1.0.3) asciidoctor-diagram-plantuml (1.2024.5) asciidoctor-diagram-batik (~> 1.17) - asciidoctor-multipage (0.0.19) - asciidoctor (>= 2.0.11, < 2.1) asciidoctor-pdf (2.3.14) asciidoctor (~> 2.0) concurrent-ruby (~> 1.1) @@ -82,6 +80,7 @@ GEM pdf-reader (~> 2.0) prawn (~> 2.2) public_suffix (6.0.0) + pygments.rb (3.0.0) racc (1.8.0) rainbow (3.1.1) rake (13.2.1) @@ -91,6 +90,7 @@ GEM nokogiri rexml (3.2.8) strscan (>= 3.0.9) + rouge (4.3.0) rubocop (1.64.1) json (~> 2.3) language_server-protocol (>= 3.17.0) @@ -111,9 +111,6 @@ GEM ruby-progressbar (1.13.0) ruby-rc4 (0.1.5) simpleidn (0.2.3) - slim (5.2.1) - temple (~> 0.10.0) - tilt (>= 2.1.0) solargraph (0.50.0) backport (~> 1.2) benchmark @@ -131,7 +128,6 @@ GEM tilt (~> 2.0) yard (~> 0.9, >= 0.9.24) strscan (3.1.0) - temple (0.10.3) thor (1.3.1) tilt (2.3.0) treetop (1.6.12) @@ -147,16 +143,16 @@ PLATFORMS DEPENDENCIES asciidoctor-diagram (~> 2.2) - asciidoctor-multipage asciidoctor-pdf base64 bigdecimal json_schemer (~> 1.0) minitest + pygments.rb rake (~> 13.0) + rouge rubocop-minitest ruby-prof - slim (~> 5.1) solargraph treetop (= 1.6.12) webrick diff --git a/arch/ext/Zbs.yaml b/arch/ext/Zbs.yaml index 5964db6d..db71ff34 100644 --- a/arch/ext/Zbs.yaml +++ b/arch/ext/Zbs.yaml @@ -9,10 +9,14 @@ Zbs: company: name: RISC-V International url: https://riscv.org + doc_license: + name: Creative Commons Attribution 4.0 International License (CC-BY 4.0) + url: https://creativecommons.org/licenses/by/4.0/ versions: - version: 1.0 state: ratified ratification_date: 2021-06 + url: https://drive.google.com/drive/u/0/folders/1_wqb-rXOVkGa6rqmugN3kwCftWDf1daU repositories: - url: https://github.com/riscv/riscv-bitmanip branch: main diff --git a/backends/ext_pdf_doc/idl_lexer.rb b/backends/ext_pdf_doc/idl_lexer.rb new file mode 100644 index 00000000..3dab3f2d --- /dev/null +++ b/backends/ext_pdf_doc/idl_lexer.rb @@ -0,0 +1,59 @@ +require "rouge" + +module Rouge + module Lexers + class Idl < RegexLexer + tag "idl" + filenames "idl", "isa" + + title "IDL" + desc "ISA Description Language" + + ws = /[ \n]+/ + id = /[a-zA-Z_][a-zA-Z0-9_]*/ + + def self.keywords + @keywords ||= Set.new %w[ + if else for return returns arguments description body function builtin enum bitfield + ] + end + + def self.keywords_type + @keywords_type ||= Set.new %w[ + Bits XReg U32 U64 String Boolean + ] + end + + # start { push :bol } + + state :bol do + rule(//) { pop! } + end + + state :root do + rule ws, Text::Whitespace + rule %r{#.*}, Comment::Single + rule %r{"[^"]*"}, Str::Double + rule %r{[A-Z][a-zA-Z0-9]*}, Name::Constant + rule %r{(?:(?:[0-9]+)|(?:XLEN))?'s?[bodh]?[0-9_a-fA-F]+}, Num + rule %r/0x[0-9a-f]+[lu]*/i, Num::Hex + rule %r/0[0-7]+[lu]*/i, Num::Oct + rule %r{\d+}, Num::Integer + rule %r{(?:true|false|\$encoding|\$pc)}, Name::Builtin + rule %r{[.,;:\[\]\(\)\}\{]}, Punctuation + rule %r([~!%^&*+=\|?:<>/-]), Operator + rule id do |m| + name = m[0] + + if self.class.keywords.include? name + token Keyword + elsif self.class.keywords_type.include? name + token Keyword::Type + else + token Name + end + end + end + end + end +end diff --git a/backends/ext_pdf_doc/tasks.rake b/backends/ext_pdf_doc/tasks.rake index f89b2b6a..13c2e948 100644 --- a/backends/ext_pdf_doc/tasks.rake +++ b/backends/ext_pdf_doc/tasks.rake @@ -48,10 +48,15 @@ module AsciidocUtils end end +file "#{$root}/ext/docs-resources/themes/riscv-pdf.yml" => "#{$root}/.gitmodules" do |t| + system "git submodule update --init ext/docs-resources" +end + rule %r{#{$root}/gen/ext_pdf_doc/.*/pdf/.*_extension\.pdf} => proc { |tname| config_name = Pathname.new(tname).relative_path_from("#{$root}/gen/ext_pdf_doc").to_s.split("/")[0] ext_name = Pathname.new(tname).basename(".pdf").to_s.split("_")[0..-2].join("_") [ + "#{$root}/ext/docs-resources/themes/riscv-pdf.yml", "#{$root}/gen/ext_pdf_doc/#{config_name}/adoc/#{ext_name}_extension.adoc" ] } do |t| @@ -60,7 +65,20 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/pdf/.*_extension\.pdf} => proc { |tname| adoc_file = "#{$root}/gen/ext_pdf_doc/#{config_name}/adoc/#{ext_name}_extension.adoc" FileUtils.mkdir_p File.dirname(t.name) - Asciidoctor.convert_file(adoc_file, backend: "pdf", safe: :safe, to_file: t.name) + sh [ + "asciidoctor-pdf", + "-w", + "-v", + "-a toc", + "-a compress", + "-a pdf-theme=#{$root}/ext/docs-resources/themes/riscv-pdf.yml", + "-a pdf-fontsdir=#{$root}/ext/docs-resources/fonts", + "-a imagesdir=#{$root}/ext/docs-resources/images", + "-r asciidoctor-diagram", + "-r #{$root}/backends/ext_pdf_doc/idl_lexer", + "-o #{t.name}", + adoc_file + ].join(" ") puts puts "Success!! File written to #{t.name}" @@ -102,6 +120,8 @@ rule %r{#{$root}/gen/ext_pdf_doc/.*/adoc/.*_extension\.adoc} => proc { |tname| erb.filename = template_path.to_s ext = arch_def.extension(ext_name) + version_num = ENV.key?("EXT_VERSION") ? ENV["EXT_VERSION"] : ext.versions.sort { |v| Gem::Version.new(v["version"]) }.last["version"] + ext_version = ext.versions.find { |v| v["version"] == version_num } FileUtils.mkdir_p File.dirname(t.name) File.write t.name, AsciidocUtils.resolve_links(arch_def.find_replace_links(erb.result(binding))) end @@ -120,6 +140,8 @@ namespace :gen do desc <<~DESC Generate PDF documentation for :extension that is defined or overlayed in :cfg + + The latest version will be used, but can be overloaded by setting the EXT_VERSION environment variable. DESC task :cfg_ext_pdf, [:extension, :cfg] do |_t, args| raise ArgumentError, "Missing required argument :extension" if args[:extension].nil? diff --git a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb index 4170fef3..5db3bb6a 100644 --- a/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb +++ b/backends/ext_pdf_doc/templates/ext_pdf.adoc.erb @@ -1,14 +1,47 @@ -= <%= ext.long_name %> - -:description: <%= ext.long_name %> -:company: <%= ext.company %> +[[header]] +:description: <%= ext.long_name %> (<%= ext.name %>) +:revdate: <%= ext_version.key?("ratification_date") ? ext_version["ratification_date"] : Date.today %> +:revnumber: <%= ext_version["version"] %> +:revmark: <%= + case ext_version["state"] + when "ratified" + <<~STATE + This document is in the http://riscv.org/spec-state[Ratified state] + \\ + + \\ + No changes are allowed. + \\ + Any desired or needed changes can be the subject of a follow-on new extension. + \\ + Ratified extensions are never revised. + \\ + STATE + when "frozen" + <<~FROZEN_STATE + This document is in the http://riscv.org/spec-state[Frozen state]. + + Change is extremely unlikely. + A high threshold will be used, and a change will only occur because of some truly + critical issue being identified during the public review cycle. + Any other desired or needed changes can be the subject of a follow-on new extension. + FROZEN_STATE + when "development" + <<~DEV_STATE + This document is in the http://riscv.org/spec-state[Development state]. + + Change should be expected + DEV_STATE + else + raise "TODO: #{ext_version["state"]} description" + end +%> +:company: <%= ext.company["name"] %> :url-riscv: https://riscv.org :doctype: book :preface-title: Licensing and Acknowledgements :colophon: :appendix-caption: Appendix -:title-logo-image: image:RISC-V-logo.svg[pdfwidth=3.25in,align=center] -:back-cover-image: image:circuit.png[opacity=25%] +:title-logo-image: image:risc-v_logo.png["RISC-V International Logo",pdfwidth=3.25in,align=center] +<%- unless ext_version["state"] == "ratified" -%> +:page-background-image: image:draft.png[opacity=20%] +<%- end -%> +:back-cover-image: image:riscv-horizontal-color.svg[opacity=25%] // Settings :experimental: :reproducible: @@ -17,30 +50,80 @@ :imagesoutdir: images :icons: font :lang: en +:example-caption: Example :listing-caption: Listing +:table-caption: Table +:figure-caption: Figure +:xrefstyle: short +:chapter-refsig: Chapter +:section-refsig: Section +:appendix-refsig: Appendix :sectnums: :toc: left -:toclevels: 4 +:toclevels: 5 :source-highlighter: pygments ifdef::backend-pdf[] -:source-highlighter: coderay +:source-highlighter: rouge endif::[] :data-uri: :hide-uri-scheme: :stem: :footnote: -:xrefstyle: short - - +:stem: latexmath +:footnote: +:le: ≤ +:ge: ≥ +:ne: ≠ +:approx: ≈ +:inf: ∞ +:csrname: envcfg +:imagesdir: images -<<< -[colophon] -== Colophon += <%= ext.long_name %> +// Preamble +<%= + case ext_version["state"] + when "ratified" + <<~RATIFIED_STATE + [WARNING] + .This document is in the link:http://riscv.org/spec-state[Ratified state] + ==== + No changes are allowed. Any desired or needed changes can be the subject of a + follow-on new extension. Ratified extensions are never revised + ==== + RATIFIED_STATE + when "frozen" + <<~FROZEN_STATE + [WARNING] + This document is in the http://riscv.org/spec-state[Frozen state]. + ==== + Change is extremely unlikely. + A high threshold will be used, and a change will only occur because of some truly + critical issue being identified during the public review cycle. + Any other desired or needed changes can be the subject of a follow-on new extension. + ==== + FROZEN_STATE + when "development" + <<~DEV_STATE + [WARNING] + This document is in the http://riscv.org/spec-state[Development state]. + ==== + Change should be expected + ==== + DEV_STATE + else + raise "TODO: #{ext_version["state"]} description" + end +%> + +[preface] +== Copyright and license information This document is released under the <%= ext.doc_license["url"] %>[<%= ext.doc_license["name"] %>]. -<<< -[acknowledgements] +Copyright <%= ext_version["ratification_date"].split("-")[0] %> by <%= ext.company["name"] %>. + +[preface] == Acknowledgements <%- ext.versions.each do |version| -%> @@ -54,7 +137,7 @@ Contributors to version <%= version["version"] %> of the specification (in alpha We express our gratitude to everyone that contributed to, reviewed or improved this specification through their comments and questions. -<<< +[preface] == Versions The following versions have been defined: @@ -151,6 +234,7 @@ Decode Variables:: <%- if i.multi_encoding? -%> RV32:: + +[source,idl] ---- <%- i.decode_variables(32).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; @@ -159,12 +243,14 @@ RV32:: RV64:: + +[source,idl] ---- <%- i.decode_variables(64).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; <%- end -%> ---- <%- else -%> +[source,idl] ---- <%- i.decode_variables(i.base.nil? ? 64 : i.base).each do |d| -%> <%= d.sext? ? 'signed ' : '' %>Bits<<%= d.size %>> <%= d.name %> = <%= d.extract %>; @@ -173,21 +259,21 @@ RV64:: <%- end -%> Operation:: -[souce,idl] +[source,idl] ---- <%= i.operation_ast(arch_def.idl_compiler).gen_adoc %> ---- Included in:: -[%header,cols="4,2,2"] +[%header,cols="4,2"] |=== |Extension |Minimum version -|Lifecycle state -|Zba (<<#zba>>) -|0.93 -|Frozen +<%- i.defined_by.each do |ext_req| -%> +|<%= ext_req.name %> +|<%= ext_req.version_requirement %> +<%- end -%> |=== <<< <%- end -%> \ No newline at end of file diff --git a/ext/docs-resources b/ext/docs-resources new file mode 160000 index 00000000..35203a4f --- /dev/null +++ b/ext/docs-resources @@ -0,0 +1 @@ +Subproject commit 35203a4f123d0be162b6b5ea213a657b594f8c36 diff --git a/lib/idl/tests/test_lexer.rb b/lib/idl/tests/test_lexer.rb new file mode 100644 index 00000000..b69cfc8b --- /dev/null +++ b/lib/idl/tests/test_lexer.rb @@ -0,0 +1,34 @@ +require "minitest/autorun" + +$root ||= (Pathname.new(__FILE__) / ".." / ".." / ".." / "..").realpath + +require_relative "#{$root}/backends/ext_pdf_doc/idl_lexer" + +# test IDL variables +class TestVariables < Minitest::Test + # include TestMixin + + def test_false + lexer = Rouge::Lexers::Idl.new + (lexer.lex "false").each do |token, chunk| + puts token + puts chunk + end + end + + def test_function + lexer = Rouge::Lexers::Idl.new + tokens = lexer.lex <<~FUNC + if (implemented?(ExtensionName::B) && (CSR[misa].B == 1'b0)) { + raise(ExceptionCode::IllegalInstruction, $encoding); + } + XReg index = shamt & (xlen() - 1); + FUNC + + tokens.each do |token, chunk| + puts token + puts chunk + end + + end +end \ No newline at end of file