Skip to content

Scoping

Julian Oppermann edited this page May 23, 2022 · 15 revisions

CoreDSL 2 defines the following three types of scopes:

  • ISA scope: Contains parameters, registers and address spaces declared in the architectural_state section as well as functions declared in the functions section.
    • The ISA scope of an InstructionSet is nested in the ISA scope of the InstructionSet referenced by the extends clause.
    • The ISA scope of a Core may have multiple parent scopes, corresponding to the ISA scopes of the InstructionSets listed in the provides clause.
  • instruction/function scope: Contains the named bitfields in the encoding specification (instructions) respectively the formal arguments (functions), and is nested in the ISA scope.
  • block scopes: Contain local variable declarations. Block scopes are nested according to the usual C rules and the control structure of the behavior specification. The outermost block scope is nested in the surrounding instruction/function scope.

The following rules apply to all scope types:

  • Every identifier can be declared at most once per scope.
  • An identifier reference binds to the first declaration that is encountered when traversing the scope hierarchy outwards.
    • Given an ISA scope with multiple parents (e.g. corresponding to Core Y provides A, B, C), the parent scopes shall be traversed in the same order as given in the provides clause (e.g. try to resolve an identifier first in A, if unsuccessful, try in B, and lastly try in C.
  • Local declarations may shadow more global ones.
  • Inside a particular scope, only declarations occurring before (according to the source code order) are visible.

Example

InstructionSet A {
    // ISA scope: param_A, foo_A
    architectural_state {
        signed<32> param_A;
    }

    instructions {
        INST_A {
            encoding: field_A[15:0] :: 0xABCD;
            behavior: 
                // instruction scope: field_A + ISA scope
            {
                // block scope: local_A, local_A2 + instruction scope
                signed<32> local_A;
                // visible here: local_A + instruction scope
                if (field_A < 42) {
                    // nested block scope 1: local_AA + block scope
                    signed<32> local_AA;
                } else {
                    // nested block scope 2: local_A + block scope
                    signed<32> local_A; // shadows local_A from block scope
                }
                signed<32> local_A2;
                // visible here: local_A, local_A2 + instruction scope
            }
        }
    }
    
    functions {
        void foo_A(signed<32> arg_A) {
            // function scope: arg_A + ISA scope
            // see instruction above for block scopes
        }
    }
}

InstructionSet B extends A {
    // ISA scope: param_B, foo_A, param_A
    architectural_state {
        signed<32> param_B;
    }
}

InstructionSet C {
    // ISA scope: param_C
    architectural_state {
        signed<32> param_C;
    }
}

Core Z provides B, C {
    // ISA scope: param_Z, param_B, foo_A, param_A, param_C
    architectural_state {
        signed<32> param_Z;
    }
}
Clone this wiki locally