// SPDX-License-Identifier: Apache-2.0

syntax = "proto3";

package firrtl;

option java_package = "firrtl";
option java_outer_classname = "FirrtlProtos";

message Firrtl {
  repeated Circuit circuit = 1;

  message SourceInfo {
    message None {
      enum Reason {
        NONE_SOURCE_INFO_REASON_UNKNOWN = 0;
        NONE_SOURCE_INFO_REASON_UNLOCATABLE = 1;
        NONE_SOURCE_INFO_REASON_SUPPRESSED = 2;
        NONE_SOURCE_INFO_REASON_DEPRECATED = 3;
      }

      // Required.
      Reason reason = 1;
    }

    message Position {
      // Required.
      string filename = 1;
      // Required.
      uint32 line = 2;
      // Required.
      uint32 column = 3;
    }

    // Required.
    oneof source_info {
      None none = 1;
      Position position = 2;
      string text = 3;
    }
  }

  message BigInt {
    // 2's complement binary representation
    bytes value = 1;
  }

  message Top {
    // Required.
    string name = 1;
  }

  message Circuit {
    repeated Module module = 1;
    repeated Top top = 2;
  }

  message Module {
    message ExternalModule {
      message Parameter {
        string id = 1;
        oneof value {
          BigInt integer = 2;
          double double = 3;
          string string = 4;
          string raw_string = 5;
        }
      }
      // Required.
      string id = 1;
      repeated Port port = 2;
      string defined_name = 3;
      repeated Parameter parameter = 4;
    }

    message UserModule {
      // Required.
      string id = 1;
      repeated Port port = 2;
      repeated Statement statement = 3;
    }

    // Required.
    oneof module {
      ExternalModule external_module = 1;
      UserModule user_module = 2;
    }
  }

  message Statement {
    message Wire {
      // Required.
      string id = 1;
      // Required.
      Type type = 2;
    }

    message Register {
      // Required.
      string id = 1;
      // Required.
      Type type = 2;
      // Required.
      Expression clock = 3;
      Expression reset = 4;
      Expression init = 5;
    }

    enum ReadUnderWrite {
      UNDEFINED = 0;
      OLD = 1;
      NEW = 2;
    }

    message Memory {
      // Required.
      string id = 1;
      // Required.
      Type type = 2;
      // Required.
      oneof depth {
        uint32 uint_depth = 3;
        BigInt bigint_depth = 9;
      }
      // Required.
      uint32 write_latency = 4;
      // Required.
      uint32 read_latency = 5;
      repeated string reader_id = 6;
      repeated string writer_id = 7;
      repeated string readwriter_id = 8;
      ReadUnderWrite read_under_write = 10;
    }

    message CMemory {
      // As alternative to using VectorType as type
      message TypeAndDepth {
        Type data_type = 1;
        BigInt depth = 2;
      }
      // Required.
      string id = 1;
      // Required.
      oneof type {
        Type.VectorType vector_type = 2;
        TypeAndDepth type_and_depth = 4;
      }
      // Required.
      bool sync_read = 3;
      ReadUnderWrite read_under_write = 5;
    }

    message Instance {
      // Required.
      string id = 1;
      // Required.
      string module_id = 2;
    }

    message Node {
      // Required.
      string id = 1;
      // Required.
      Expression expression = 2;
    }

    message When {
      // Required.
      Expression predicate = 1;
      repeated Statement consequent = 2;
      repeated Statement otherwise = 3;
    }

    message Stop {
      // Required.
      int32 return_value = 1;
      // Required.
      Expression clk = 2;
      // Required.
      Expression en = 3;
    }

    message Printf {
      // Required.
      string value = 1;
      repeated Expression arg = 2;
      // Required.
      Expression clk = 3;
      // Required.
      Expression en = 4;
    }

    enum Formal {
      ASSERT = 0;
      ASSUME = 1;
      COVER = 2;
    }

    message Verification {
      // Required.
      Formal op = 1;
      // Required.
      Expression clk = 2;
      // Required.
      Expression cond = 3;
      // Required.
      Expression en = 4;
      // Required.
      string msg = 5;
    }

    message Skip {
      // Empty
    }

    message Connect {
      // This should be limited to Reference, SubField, SubIndex, or SubAccess.
      // Required.
      Expression location = 1;
      // Required.
      Expression expression = 2;
    }

    message PartialConnect {
      // This should be limited to Reference, SubField, SubIndex, or SubAccess.
      // Required.
      Expression location = 1;
      // Required.
      Expression expression = 2;
    }

    message IsInvalid {
      // Required.
      Expression expression = 1;
    }

    message MemoryPort {
      enum Direction {
        MEMORY_PORT_DIRECTION_UNKNOWN = 0;
        MEMORY_PORT_DIRECTION_INFER = 1;
        MEMORY_PORT_DIRECTION_READ = 2;
        MEMORY_PORT_DIRECTION_WRITE = 3;
        MEMORY_PORT_DIRECTION_READ_WRITE = 4;
      }

      // Required.
      Direction direction = 1;
      // Required.
      string id = 2;
      // Required.
      string memory_id = 3;
      // Required.
      Expression memory_index = 4;
      // Required.
      Expression expression = 5;
    }

    message Attach {
      repeated Expression expression = 1;
    }

    // Required.
    oneof statement {
      Wire wire = 1;
      Register register = 2;
      Memory memory = 3;
      CMemory cmemory = 4;
      Instance instance = 5;
      Node node = 6;
      When when = 7;
      Stop stop = 8;
      Printf printf = 10;
      Skip skip = 14;
      Connect connect = 15;
      PartialConnect partial_connect = 16;
      IsInvalid is_invalid = 17;
      MemoryPort memory_port = 18;
      Attach attach = 20;
    }

    SourceInfo source_info = 19;
  }

  // Using proto3 means that there is no has* method for primitives. This
  // necesitates boxing width values because there are cases where a width of
  // zero (the default value of uint32) is a valid width.
  message Width {
    // Required
    uint32 value = 1;
  }

  message Type {
    message UIntType {
      Width width = 1;
    }

    message SIntType {
      Width width = 1;
    }

    message ClockType {
      // Empty.
    }

    message AsyncResetType {
      // Empty.
    }

    message ResetType {
      // Empty.
    }

    message BundleType {
      message Field {
        // Required.
        bool is_flipped = 1;
        // Required.
        string id = 2;
        // Required.
        Type type = 3;
      }
      repeated Field field = 1;
    }

    message VectorType {
      // Required.
      Type type = 1;
      // Required.
      uint32 size = 2;
    }

    message FixedType {
      Width width = 1;
      Width point = 2;
    }

    message AnalogType {
      Width width = 3;
    }

    // Required.
    oneof type {
      UIntType uint_type = 2;
      SIntType sint_type = 3;
      ClockType clock_type = 4;
      BundleType bundle_type = 5;
      VectorType vector_type = 6;
      FixedType fixed_type = 7;
      AnalogType analog_type = 8;
      AsyncResetType async_reset_type = 9;
      ResetType reset_type = 10;
    }
  }

  message Port {
    enum Direction {
      PORT_DIRECTION_UNKNOWN = 0;
      PORT_DIRECTION_IN = 1;
      PORT_DIRECTION_OUT = 2;
    }

    // Required.
    string id = 1;
    // Required.
    Direction direction = 2;
    // Required.
    Type type = 3;
  }

  message Expression {
    message Reference {
      // Required.
      string id = 1;
    }

    message IntegerLiteral {
      // Base 10 value. May begin with a sign (+|-). Only zero can begin with a
      // '0'.
      // Required
      string value = 1;
    }

    message UIntLiteral {
      // Required.
      IntegerLiteral value = 1;
      Width width = 2;
    }

    message SIntLiteral {
      // Required.
      IntegerLiteral value = 1;
      Width width = 2;
    }

    message FixedLiteral {
      BigInt value = 1;
      Width width = 2;
      Width point = 3;
    }

    message ValidIf {
      // Required.
      Expression condition = 1;
      // Required.
      Expression value = 2;
    }

    message Mux {
      // Required.
      Expression condition = 1;
      // Required.
      Expression t_value = 2;
      // Required.
      Expression f_value = 3;
    }

    message SubField {
      // Required.
      Expression expression = 1;
      // Required.
      string field = 2;
    }

    message SubIndex {
      // Required.
      Expression expression = 1;
      // Required.
      IntegerLiteral index = 2;
    }

    message SubAccess {
      // Required.
      Expression expression = 1;
      // Required.
      Expression index = 2;
    }

    message PrimOp {

      enum Op {
        OP_UNKNOWN = 0;
        OP_ADD = 1;
        OP_SUB = 2;
        OP_TAIL = 3;
        OP_HEAD = 4;
        OP_TIMES = 5;
        OP_DIVIDE = 6;
        OP_REM = 7;
        OP_SHIFT_LEFT = 8;
        OP_SHIFT_RIGHT = 9;
        OP_DYNAMIC_SHIFT_LEFT = 10;
        OP_DYNAMIC_SHIFT_RIGHT = 11;
        OP_BIT_AND = 12;
        OP_BIT_OR = 13;
        OP_BIT_XOR = 14;
        OP_BIT_NOT = 15;
        OP_CONCAT = 16;
        OP_LESS = 17;
        OP_LESS_EQ = 18;
        OP_GREATER = 19;
        OP_GREATER_EQ = 20;
        OP_EQUAL = 21;
        OP_PAD = 22;
        OP_NOT_EQUAL = 23;
        OP_NEG = 24;
        OP_XOR_REDUCE = 26;
        OP_CONVERT = 27;
        OP_AS_UINT = 28;
        OP_AS_SINT = 29;
        OP_EXTRACT_BITS = 30;
        OP_AS_CLOCK = 31;
        OP_AS_FIXED_POINT = 32;
        OP_AND_REDUCE = 33;
        OP_OR_REDUCE = 34;
        OP_INCREASE_PRECISION = 35;
        OP_DECREASE_PRECISION = 36;
        OP_SET_PRECISION = 37;
        OP_AS_ASYNC_RESET = 38;
        OP_WRAP = 39;
        OP_CLIP = 40;
        OP_SQUEEZE = 41;
        OP_AS_INTERVAL = 42;
      }

      // Required.
      Op op = 1;
      repeated Expression arg = 2;
      repeated IntegerLiteral const = 3;
    }

    reserved 5;

    // Required.
    oneof expression {
      Reference reference = 1;
      UIntLiteral uint_literal = 2;
      SIntLiteral sint_literal = 3;
      FixedLiteral fixed_literal = 11;
      ValidIf valid_if = 4;
      //ExtractBits extract_bits = 5;
      Mux mux = 6;
      SubField sub_field = 7;
      SubIndex sub_index = 8;
      SubAccess sub_access = 9;
      PrimOp prim_op = 10;
    }
  }
}
