SLICC - Version 0.3 Design Document - January 17, 1999
Milo Martin and Dan Sorin

Question: Rethinking of support for profiling the transactions

Question: How do we deal with functions/methods and resources

Comment: We need to discuss the sequencer interface so it can work now
         and for the speculative version buffer.

Overview
--------

We are in the process of designing and implementing SLICC v0.3, an
evolution of SLICC v0.2.  The new design includes capabilities for
design of multilevel cache hierarchies including the specification of
multiple protocol state machines (PSMs) and the queues which connect
these PSMs and the network.  We actually believe that most of the
network and network topology, including the ordered network, can be
expressed using the new hierarchical extensions to the language.

In addition, many implicit aspects of the language will be eliminated
in favor of explicit declarations.  For example functions, queues, and
objects declarations such as "cacheMemory" and "TBETable" will be
explicitly declared.  This will allow for full static type checking
and easier extension for the language.  Event triggering will be part
of "in_port" declarations and not "event" declarations.  Finally, many
less fundamental, but important, features and internal code
improvements will be enhanced.

SLICC History
-------------

v0.1 - Initially the language only handled the generation of the PSM
       transition table logic.  All actions and event triggering were
       still coded in C++.  At this point it was still called, "the
       language."

v0.2 - Extended the language to include a simple C like syntax for
       specifying actions, event triggering, and manipulating queues
       and state elements.  This version was the first version of the
       language known as SLICC (suggested by Amir) and was used for
       the Multifacet ISCA 2000 submission.

v0.3 - Development effort started January 2000.  Intended features and
       enhancements are described by this document.

Specifying Hierarchical Designs
-------------------------------

Right now all of our protocols have two tables, a processor/cache PSM
and a directory PSM.  In v0.2 this is a rigid requirement and
the names are implicit.  SLICC v0.3 will allow for an arbitrary number
of different PSMs.

The most significant improvement in v0.3 is the ability for the user
to define an arbitrary set of interconnected PSMs.  PSMs may include
an L1 cache controller, L2 cache controller, directory controller,
speculative version buffer, network interface, etc.  There are a
couple of "primitive PSMs" such as the sequencer.

There will be a notion of a "node" of the system.  In a node, each PSM
will be instantiated and connected together with queues.  For example,
assume we define a PSMs and want to create a queue of RequestMessages
to communicate between it and the network.

  machine(CacheController) {
    ...
    out_port(to_network, RequestMessage, "To the network", desc="...");
    ...
  }

  CacheController cache, desc="...";

  connect(cache.to_network, network.from_cache, ordered="yes", desc="...");

Explicit State Manipulation
---------------------------

As before, PSMs have states, events, and transitions. New in v0.3 each
PSM must have user defined methods for get_state(address) and
set_state(address, state), and these methods are written explicitly,
instead of being implicit functions of memory states (e.g., our
current implementation which implicitly uses the TBE state if there is
a TBE or uses the cache state).  Functions have a return value,
procedures do not.  Function calls are expressions, procedure calls
are statements.  All function and procedure parameters are considered
pass-by-value.

  procedure set_state(Address addr, State state) {
    ...
  }

  function State get_state(Address addr) {
    ...
  }

Explicit Declaration
--------------------

PSMs reference or declare structures, such as queues, ports, cache
memories, main memory, TBEs, write buffers, etc.  These primitive
types and structures are written in C++, and their semantics are still
specified by the C++ coder.  Examples of these primitive types include
"CacheMemory," "TBETable," as well as various types of queues.

One major difference is that in v0.3 the interface for all of these
primitive objects will be declared (but not defined) in the SLICC
language.  This also allows adding primitive structures by defining a
C++ implementation and a SLICC interface specification.  This will
make the language much more extensible.  Specifying the interface of
these primitive types, structures, and queues in SLICC will eliminate
much of the implicit semantics that is currently hiding in the
controllers.

The interface declaration might be in one file and shared between all
protocols.  The object instantiation would be internal to each PSM
that requires a cache memory.  The syntax for messages will also be
enhanced by using this new syntax.  Notice the support for default
values.

  structure(CacheMemory, "Cache memory", desc="...") {
    void cache_change_state(Address addr, State state), desc="...";
    Data dataBlk, default="", desc="";
    bool cache_avail(Address addr), desc="...";
    Address cache_probe(Address addr), desc="...";
    void cache_allocate(Address addr), desc="...";
  }

  CacheMemory L1cacheMemory, desc="...";

Structure specification is going to require the introduction of an
object model in the language.  The "." (dot) operator is going to be
extended beyond the use as structure element access, but also allow
for a object method call syntax similar to C++ and Java.

  L1cacheMemory.cache_allocate(addr);

Polymorphism
------------

We are also going to want to allow for polymorphism for many of the
structures.  We already have a limited degree of polymorphism between
different protocols by using the same cache memory structure with
different "CacheEntry" types in each protocol.  Now that we are going
to have multiple levels of cache, each requiring slightly different
state bits, we are going to want to specify cache memory structures
which have different "CacheEntry" types in the same protocol.  To do
this right, this is going to require adding full polymorphism support
to the language.  Right now we imagine something like C++'s templates,
since they are a more natural fit to hardware synthesis in the future.

Type Checker
------------

All of the above substantially complicates our type system by
requiring more types and scoping rules.  As a step towards
understanding the implications of the type system, a type checking
system will be implemented.  This is a hard requirement if we are ever
to distribute the system since receiving compile time errors in the
generated code is not acceptable.  In order to ensure that we don't
accidentally design a language that is not statically type checkable,
it is important to add the type checker sooner rather than later.

Event Triggering
----------------

In v0.2, PSM events were individually specified as sets of conditions.
The following SLICC v0.2 code is a simplified example from the origin
protocol.

  event(Dir_data_ack_0, "Data ack 0", desc="... ack count == 0") {
    if (queue_ready(responseNetwork)) {
      peek(responseNetwork, ResponseMsg) {
        if(in_msg.NumPendingAcks == 0) {
          trigger(in_msg.Address);
        }
      }
    }
  }

  event(Dir_data_ack_not_0, "Data ack not 0", desc="... ack count != 0") {
    if (queue_ready(responseNetwork)) {
      peek(responseNetwork, ResponseMsg) {
        if(in_msg.NumPendingAcks != 0) {
          trigger(in_msg.Address);
        }
      }
    }
  }

The above code defines the exact conditions for the events to be
triggered.  This type of event specification led to redundant code and
numerous bugs where conditions for different events were not
completely orthogonal.

In v0.3, events will be declared with no accompanying code (similar to
how states are specified). Instead, the code that determines which
event is triggered will be part of each incoming port's declaration.
This approach should eliminate redundancy and bugs in trigger
conditions.  The v0.3 code for the above would look like:

  event(Dir_data_ack_0, "Data ack 0", desc="... ack count = 0");
  event(Dir_data_ack_not_0, "Data ack not 0", desc="... ack count != 0");

  in_port(responseNetwork, ResponseMsg, "Response Network", desc="...") {
    if(in_msg.NumPendingAcks == 0) {
      trigger(Dir_data_ack_0, in_msg.Address);
    } else {
      trigger(Dir_data_ack_not_0, in_msg.Address);
    }
  }

Notice that one no longer needs to explicitly check if the queue is
ready or to perform the peek operation.

Also notice that the type of messages that arrives on the port is
explicitly declared.  All ports, incoming and outgoing, are now
explicitly type channels.  You will still be required to include the
type of message when manipulating the queue.  The type specified will
be statically type checked and also acts as self-documenting code.

Other Improvements
------------------

There will be a number of other improvements in v0.3 such as general
performance tuning and clean up of the internals of the compiler.  The
compiler will be modified to operate on multiple files.  In addition,
the abstract syntax tree internal to the code will need to be extended
to encompass more information, including information parsed in from
multiple files.

The affiliates talk and the document for the language should also be
updated to reflect the changes in the new version.

Looking Forward
---------------

When designing v0.3 we are keeping future plans in mind.

- When our designs of the multilevel cache hierarchy are complete, we
  expect to have a large amount of replication between the protocols
  and caches controllers within a protocol.  For v0.4 we hope to look
  at the patterns that have evolved and look for ways in which the
  language can capture these patterns.  Exploiting reuse will provide
  quicker protocol development and maintainability.

- By keeping the specification structural, we are looking towards
  generating VHDL/Verilog from SLICC.  The type system will help this,
  as will more explicit instantiation and declaration of types and
  structures.  The structures now written in C++ (sequencer, network,
  cache arrays) will be ported to the HDL we select.  The rest of the
  controllers will be generated by the compiler.  At first the
  generated controller will not be optimized.  I believe that with
  more effort we can automatically generate reasonably optimized,
  pipelined implementation of the controllers.

Implementation Plan
-------------------

- HTML generator
- Extend internal parser AST nodes
- Add get_state function and set_state procedure declarations
- Move trigger logic from events to in_ports
- Types
  - Change type declaration syntax
  - Declare primitive types and corresponding C++ types
  - Add default values to structures and types
  - Add object method call syntax
  - Write type checker
- Documentation
  - Revise document
  - Update presentation

Document History
----------------

$Id: SLICC_V03.txt,v 3.0 2000/09/12 20:27:59 sorin Exp $

$Log: SLICC_V03.txt,v $
Revision 3.0  2000/09/12 20:27:59  sorin
Version 3.0 signifies a checkpoint of the source tree right after the
final draft of the ASPLOS '00 paper.

Revision 1.1.1.1  2000/03/09 10:18:38  milo
Initial import

Revision 2.0  2000/01/19 07:21:13  milo
Version 2.0

Revision 1.5  2000/01/18 10:26:24  milo
Changed the SLICC parser so that it generates a full AST.  This is the
first step in moving towards v0.3

Revision 1.4  2000/01/17 18:36:15  sorin
*** empty log message ***

Revision 1.3  2000/01/15 10:30:16  milo
Added implementation list

Revision 1.2  2000/01/15 08:11:44  milo
Minor revisions

Revision 1.1  2000/01/15 07:14:17  milo
Converted Dan's first draft into a text file.  Significant
modifications were made.

