clarify
[libreriscv.git] / isa_conflict_resolution.mdwn
index b84a8a1781149d922f54dcdec37c918a9f30ef03..5538a7add9af251063c15808234636ec3a0cc313 100644 (file)
@@ -1,5 +1,37 @@
 # Resolving ISA conflicts and providing a pain-free RISC-V Standards Upgrade Path
 
+## Executive Summary
+
+A non-invasive backwards-compatible change to make mvendorid and marchid
+being read-only to be a formal declaration of an architecture having no
+Custom Extensions, and being permitted to be WARL in order to support
+multiple simultaneous architectures on the same processor (or per hart
+or harts) permits not only backwards and forwards compatibility with
+existing implementations of the RISC-V Standard, not only permits seamless
+transitions to future versions of the RISC-V Standard (something that is
+not possible at the moment), but fixes the problem of clashes in Custom
+Extension opcodes on a global worldwide permanent and ongoing basis.
+
+Summary of impact and benefits:
+
+* Implementation impact for existing implementations (even though
+  the Standard is not finalised) is zero.
+* Impact for future implementations compliant with (only one) version of the
+  RISC-V Standard is zero.
+* Benefits for implementations complying with (one or more) versions
+  of the RISC-V Standard is: increased customer acceptance due to
+  a smooth upgrade path at the customer's pace and initiative vis-a-vis
+  legacy proprietary software.
+* Benefits for implementations deploying multiple Custom Extensions
+  are a massive reduction in NREs and the hugely reduced ongoing software
+  toolchain maintenance costs plus the benefit of having security updates
+  from upstream software sources due to
+  *globally unique identifying information* resulting in zero binary
+  encoding conflicts in the toolchains and resultant binaries
+  *even for Custom Extensions*.
+
+## Introduction
+
 In a lengthy thread that ironically was full of conflict indicative
 of the future direction in which RISC-V will go if left unresolved,
 multiple Custom Extensions were noted to be permitted free rein to
@@ -235,7 +267,7 @@ turn the custom instruction into an actual binary-encoding (plus
 binary-encoding of the context-switching information).  (**TBD, Jacob,
 separate page?  review this para?**)
 
-# mvendorid/marchid WARL
+# mvendorid/marchid WARL <a name="mvendor_marchid_warl"></a>
 
 (Summary: the only idea that meets the full requirements.  Needs
  toolchain backup, but only when the first chip is released)
@@ -284,8 +316,8 @@ On this latter point, it was observed that MISA already switches out entire
 sets of instructions (interacts at the "decode" phase).  The difference
 between what MISA does and the mvendor/march-id WARL idea is that whilst
 MISA only switches instruction decoding on (or off), the WARL idea
-*redirects* encoding, to *different* engines, fortunately in a deliberately
-mutually-exclusive fashion.
+*redirects* encoding, effectively to *different* simultaneous engines,
+fortunately in a deliberately mutually-exclusive fashion.
 
 Implementations would therefore, in each Extension (assuming one separate
 "decode" engine per Extension), simply have an extra (mutually-exclusively
@@ -293,8 +325,8 @@ enabled) wire in the AND gate for any given binary encoding, and in this
 way there would actually be very little impact on the latency.  The assumption
 here is that there are not dozens of Extensions vying for the same binary
 encoding (at which point the Fabless Semi Company has other much more
-pressing issues to deal with that make resolving encoding conflicts trivial
-by comparison).
+pressing issues to deal with that make resolving binary encoding conflicts
+trivial by comparison).
 
 Also pointed out was that in certain cases pipeline stalls could be introduced
 during the switching phase, if needed, just as they may be needed for
@@ -302,28 +334,37 @@ correct implementation of (mandatory) support for MISA.
 
 **This is the only one of the proposals that meet the full requirements**
 
-# ioctl-like
+Update 29apr2018:
+
+* In cases where mvendorid and marchid are WARL, the mvendorid-marchid becomes
+  part of the execution context that must be saved (and switched as necessary)
+  just like any other state / CSR.
+* When any trap exception is raised the context / state *must not* be altered
+  (so that it can be properly saved, if needed, by the exception handler)
+  and that includes the current mvendorid-marchid tuple.  This leads to some
+  interesting situations where a hart could conceivably be directed
+  to a set of trap handler binary instructions that the current
+  mvendorid-marchid setting is incapable of correctly interpreting.
+  To fix this it will be necessary for implementations (hardware /
+  software) to set up separate per-mvendorid-marchid trap handlers and
+  for the hardware (or software) to switch to the appropriate trap "set"
+  when the mvendorid-marchid is written to.  The switch to a different
+  "set" will almost undoubtedly require (transparent) hardware assistance.
+* It's been noted that there may be certain legitimate cases where an
+  mvendorid-marchid should *specifically* not be tested for RISC-V
+  Certification Compliance: native support for foreign architectures
+  (not related to the JIT Extension: *actual* full entire non-RISC-V
+  foreign instruction encoding).  Exactly how this would work (vis-a-vis
+  Compliance) needs discussion, as it would be unfortunate and
+  undesirable for a hybrid processor capable of executing more than one
+  hardware-level ISA support to not be permitted to receive RISC-V
+  Certification Compliance.
+
+# ioctl-like <a name="ioctl-like"></a>
 
 (Summary: good solid orthogonal idea.  See [[ioctl]] for full details)
 
-==RB===
-
-This proposal adds a standardised extension interface to the RV instruction set by introducing a fixed small number (e.g. 8) of "overloadable" R-type opcodes ext_ctl0, .. ext_ctl7. Each takes a process local interface cookie in rs1. Based on the cookie, the CPU routes the "overloaded" instructions to a "device" on or off the CPU that implements the actual semantics. 
-
-The cookie is "opened" with an additional r-type instruction ext_open that takes a 20 bit identifier and "closed" with an  ext_close instruction. The implementing hardware device can use the cookie to reference internal state. Thus, interfaces may be statefull.
-
-CPU's and devices may implement several interfaces, indeed, are expected to. E.g. a single hardware device might expose a functional interface with 6 overloaded instructions, expose configuration with two highly device specific management interfaces with 8 resp. 4 overloaded instructions, and respond to a standardised save state interface with 4 overloaded instructions.
-
-Having a standardised overloadable interface simply avoids much of the need for isa extensions for hardware with non standard interfaces and semantics. This is analogous to the way that the standardised overloadable ioctl interface of the kernel almost completely avoids the need for extending the kernel with syscalls for the myriad of hardware devices with their specific interfaces and semantics.  
-
-Since the rs1 input of the overloaded  ext_ctl instruction's are taken by the interface cookie, they are restricted in use compared to a normal R-type instruction (it is possible to pass 12 bits of additional info by or ing it with the cookie). Delegation is also expected to come at a small additional performance price compared to a "native" instruction. This should be an acceptable tradeoff in most cases. 
-
-The expanded flexibility comes at the cost: the standard can specify the semantics of the delegation mechanism and the interfacing with the rest of the cpu, but the actual semantics of the overloaded instructions can only be defined by the designer of the interface. Likewise, a device can be conforming as far as delegation and interaction with the CPU is concerned, but whether the hardware is conforming to the semantics of the interface is outside the scope of spec. Being able to specify that semantics using the methods used for RV itself is clearly very valuable. One impetus for doing that is using it for purposes of its own, effectively freeing opcode space for other purposes. Also, some interfaces may become de facto or de jure standards themselves, necessitating hardware to implement competing interfaces. I.e., facilitating a free for all, may lead to standards proliferation. C'est la vie.  
-
-The only "ISA-collisions" that can still occur are in the 20 bit (~10^6) interface identifier space, with 12 more bits to identify a device on a hart that implements the interface. One suggestion is setting aside 2^19 id's that are handed out for a small fee by a central (automated) registration (making sure the space is not just claimed), while the remaining 2^19 are used as a good hash on a long, plausibly globally unique human readable interface name. This gives implementors the choice between a guaranteed private identifier paying a fee, or relying on low probabilities. The interface identifier could also easily be extended to 42 bits on RV64. 
-
-
-====End RB==
+NOTE: under discussion.
 
 This proposal basically mirrors the concept of POSIX ioctls, providing
 (arbitrarily) 8 functions (opcodes) whose meaning may be over-ridden
@@ -331,131 +372,6 @@ in an object-orientated fashion by calling an "open handle" (and close)
 function (instruction) that switches (redirects) the 8 functions over to
 different opcodes.
 
-
-The "open handle" opcode takes a GUID (globally-unique identifier)
-and an ioctl number, and stores the UUID in a table indexed by the
-ioctl number:
-
-    handle_global_state[8] # stores UUID or index of same 
-
-    def open_handle(uuid, ioctl_num): 
-          handle_global_state[ioctl_num] = uuid 
-
-    def close_handle(ioctl_num): 
-          handle_global_state[ioctl_num] = -1 # clear table entry
-
-         
-"Ioctls" (arbitrarily 8 separate R-type opcodes) then perform a redirect
-based on what the global state for that numbered "ioctl" has been set to:
-
-    def ioctl_fn0(*rargs): # star means "take all arguments as a tuple"
-        if handle_global_state[0] == CUSTOMEXT1UUID: 
-           CUSTOMEXT1_FN0(*rargs) # apply all arguments to function 
-        elif handle_global_state[0] == CUSTOMEXT2UUID: 
-           CUSTOMEXT2_FN0(*rargs) # apply all arguments to function 
-        else:
-            raise Exception("undefined opcode")
-
-=== RB ==
-
-not quite I think. It is more like
-
-    def A_shutdown(cookie, data):
-       ...
-
-    def A_init(data)
-
-    def A_do_stuff(cookie, data):
-       ...
-
-    def A_do_more_stuff(cookie, data):
-       ...
-
-    def B_do_stuff(cookie, data):
-       ...
-
-    def B_shutdown(cookie, data)
-       ...
-
-    interfaceA = {
-                  shutdown: A_shutdown,
-                  init:     A_init,
-                  ctl0:     A_do_stuff, 
-                  ctl1:     A_do_more_stuff
-                 }
-
-    interfaceB = {
-                  shutdown: B_shutdown,
-                  init:     B_init,
-                  ctl0:     B_do_stuff
-                 }
-
-    cpu_interfaces = {
-                  0xABCD: interfaceA,
-                  0x1234: interfaceB
-                 }
-
-    cpu_open_handles = {}
-  
-    __handleId = 0
-    def new_unused_handle_id()
-        __handle = __handle + 1
-        return __handle
-         
-    def ext_open(uuid, data):
-        interface = cpu_interface[uuid]
-        if interface == NIL:
-            raise Exception("Unrecognised interface")
-        
-        handleId = new_unused_handle_id()
-        cpu_open_handles[handleId] = (interface, CurrentVirtualMemoryAddressSpace).
-        cookie = A_init(data)
-
-        return (handle_id, cookie)
-
-    def ext_close(handle, data):
-        (handleId, cookie) = handle
-        intf_VMA = cpu_open_handles[handleId]
-        if intf_VMA == NIL:
-             return -1
-
-        (interface, VMA) = intf_VMA
-        if VMA != CurrentVirtualMemoryAddressSpace:
-             return -1
-        assert(interface != NIL)
-        shutdown = interface["shutdown"]
-        if shutdown != NIL:
-             err = interface.shutdown(cookie, data)
-             if err != 0:
-                 return err
-        cpu_open_handles[handleId] = NIL
-        return 0
-
-    def ext_ctl0(handle, data):
-        (handleId, cookie) = handle
-        intf_VMA = cpu_open_handles[handleId]
-        if intf_VMA == NIL:
-             raise Exception("unknown interface")   
-
-        (interface, VMA) = intf_VMA
-        if VMA != CurrentVirtualMemoryAddressSpace: 
-             raise Exception("unknown interface")  #Disclosing that the interface exists in different address is security hole 
-
-        assert(interface != NIL)
-        ctl0 = interface["ctl0"]
-        if ctl0 == NIL:
-            raise Exception("Invalid Instruction")
-
-        return ctl0(cookie, data)
-       
-        
-   The other ext_ctl's are similar. 
-        
-==End RB==
-
-
-
-      
 The proposal is functionally near-identical to that of the mvendor/march-id
 except extended down to individual opcodes.  As such it could hypothetically
 be proposed as an independent Standard Extension in its own right that extends
@@ -477,8 +393,6 @@ being worthwhile in its own right, and standing on its own merits and
 thus definitely worthwhile pursuing, it is non-trivial and much more
 invasive than the mvendor/march-id WARL concept.
 
-
-
 # Comments, Discussion and analysis
 
 TBD: placeholder as of 26apr2018
@@ -542,7 +456,8 @@ So to summarise:
   cannot take a back seat.  If it does, clear historical precedent shows
   100% what the outcome will be (1).
 * Making the mvendorid and marchid CSRs WARL solves the problem in a
-  minimal to zero-disruptive fashion.
+  minimal to zero-disruptive backwards-compatible fashion that provides
+  indefinite transparent *forwards*-compatibility.
 * The retro-fitting cost onto existing implementations (even though the
   specification has not been finalised) is zero to negligeable
   (only changes to words in the specification required at this time:
@@ -557,10 +472,10 @@ So to summarise:
 * Compliance Testing is straightforward and allows vendors to seek and
   obtain *multiple* Compliance Certificates with past, present and future
   variants of the RISC-V Standard (in the exact same processor,
-  simultaneously), in order to support legacy customers and provide
-  same customers with a way to avoid "impossible-to-make" decisions that
-  throw out ultra-expensive multi-decade proprietary legacy software at
-  the same as the (legacy) hardware.
+  simultaneously), in order to support end-customer legacy scenarios and
+  provide the same with a way to avoid "impossible-to-make" decisions that
+  throw out ultra-costly multi-decade-investment in proprietary legacy
+  software at the same as the (legacy) hardware.
 
 -------