// Copyright lowRISC contributors (OpenTitan project).
// Licensed under the Apache License, Version 2.0, see LICENSE for details.
// SPDX-License-Identifier: Apache-2.0
//
// Register Package auto-generated by `rdl2ot` containing data structure

package {{ name }}_reg_pkg;

{%- for item in parameters %}
  {%- if loop.first %}

  // Param list
  {%- endif %}
  parameter {{ item.type|lower }} {{ item.name }} = {{ item.value }};
{%- endfor %}

  // Address widths within the block
{%- for interface in interfaces %}
  {%- set addr_with_name = (interface.name|title if interface.name else "Block") + "Aw"  %}
  parameter int {{ addr_with_name }} = {{ interface.addr_width }};
{%- endfor %}

  // Number of registers for every interface
{%- for interface in interfaces %}
  parameter int NumRegs{{ interface.name|title }} = {{ interface.num_regs }};
{%- endfor %}


{%- if alerts|length > 0 %}

  // Alert indices
  typedef enum int {
{%- for alert in alerts %}
    Alert{{ alert | camelcase  }}Idx = {{ loop.index0 }}{{ "," if not loop.last }}
{%- endfor %}
  } {{ name | lower }}_alert_idx_t;
{%- endif %}

{%- for interface in interfaces %}
  {%- set registers = interface.regs %}
  {%- set interface_name = ("_" + interface.name)|lower if interface.name %}
  {%- set addr_with_name = (interface.name|title if interface.name else "Block") + "Aw"  %}
  {%- set num_regs_digits = interface.num_regs | string | length %}
  {%- set printed = namespace(header = false) %}

  {%- if registers|length > 0 %}

  ///////////////////////////////////////////////
  // Typedefs for registers for {{ interface.name|lower }} interface //
  ///////////////////////////////////////////////
    {%- for reg in registers -%}
      {%- if reg.hw_readable %}
        {%- set fields = reg.fields[0:1] if reg.opentitan.is_homogeneous else reg.fields  %}
        {%- set indent = "  " if fields|length > 1 %}

  typedef struct packed {
        {%- for field in fields|reverse if field.hw_readable %}
          {%- if fields|length > 1 %}
    struct packed {
          {%- endif %}
          {%- set bits = "[{}:0]".format(field.width - 1) if field.width > 1 else " " %}
    {{ indent }}logic {{ "{:<6}".format(bits) }} q;
          {%- if field.swmod %}
    {{ indent }}logic        qe;
          {%- endif %}
          {%- if reg.hwre or (reg.shadowed and reg.external) %}
    {{ indent }}logic        re;
          {%- endif %}
          {%- if fields|length > 1 %}
    } {{ field.name|lower }};
          {%- endif %}
        {%- endfor %}
  } {{ name }}_reg2hw_{{ reg.name|lower }}_{{"m" if reg.is_multireg}}reg_t;
      {%- endif %}
    {%- endfor %}
  {%- endif %}

  {%- if registers|length > 0 %}
    {%- for reg in registers  %}
      {%- if reg.hw_writable %}
        {%- set fields = reg.fields[0:1] if reg.opentitan.is_homogeneous else reg.fields  %}
        {%- set indent = "  " if fields|length > 1 %}

  typedef struct packed {
        {%- for field in fields|reverse  %}
          {%- if field.hw_writable %}
            {%- if fields|length > 1 %}
    struct packed {
            {%- endif %}
            {%- set bits = "[{}:0]".format(field.width - 1) if field.width > 1 else " " %}
    {{ indent }}logic {{ "{:<6}".format(bits) }} d;
            {%- if not reg.external %}
    {{ indent }}logic {{ "{:<6}".format("") }} de;
            {%- endif %}
            {%- if fields|length > 1 %}
    } {{ field.name|lower }};
            {%- endif %}
          {%- endif %}
        {%- endfor %}
  } {{ name }}_hw2reg_{{ reg.name|lower }}_{{"m" if reg.is_multireg}}reg_t;
      {%- endif %}
    {%- endfor %}
  {%- endif %}

  {%- set printed.header = false %}
  {%- for reg in registers  %}
    {%- if reg.hw_readable %}
      {%- if not printed.header %}

  // Register -> HW type for {{ interface.name|lower }} interface
  typedef struct packed {
        {%- set printed.header = true %}
      {%- endif %}
      {%- set width = reg.fields|length * reg.offsets|length if reg.opentitan.is_homogeneous and reg.is_multifields else reg.offsets|length %}
      {%- set bits = " [{}:0]".format(width - 1) if reg.is_multireg or (reg.opentitan.is_homogeneous and reg.is_multifields) %}
    {{ "{}_reg2hw_{}_{}reg_t{} {};".format(name, reg.name, "m" if reg.is_multireg, bits, reg.name)|lower }}
    {%- endif %}
  {%- endfor %}
  {%- if printed.header %}
  } {{ name }}{{interface_name|lower}}_reg2hw_t;
  {%- endif %}

  {%- set printed.header = false %}
  {%- for reg in registers  %}
    {%- if reg.hw_writable %}
      {%- if not printed.header %}

  // HW -> register type for {{ interface.name|lower}} interface
  typedef struct packed {
        {%- set printed.header = true %}
      {%- endif %}
      {%- set width = reg.fields|length if reg.opentitan.is_homogeneous and reg.is_multifields else reg.offsets|length %}
      {%- set bits = " [{}:0]".format(width - 1) if reg.is_multireg %}
    {{ "{}_hw2reg_{}_{}reg_t{} {};".format(name, reg.name, "m" if reg.is_multireg, bits, reg.name)|lower }}
    {%- endif %}
  {%- endfor %}
  {%- if printed.header %}
  } {{ name }}{{interface_name}}_hw2reg_t;
  {%- endif %}

  {%- set printed.header = false %}
    {%- set addr_width = interface.addr_width %}
    {%- for reg in registers %}
      {%- for offset in reg.offsets %}
        {%- set index = "_{}".format(loop.index0) if reg.offsets|length > 1 %}
        {%- set offset_name = "{}_{}{}_OFFSET".format(name, reg.name, index)|upper %}
        {%- if not printed.header %}

  // Register offsets for {{ interface.name|lower}} interface
          {%- set printed.header = true %}
        {%- endif %}
  parameter logic [{{ addr_with_name }}-1:0] {{ "{} = {}'h {:x}".format(offset_name, addr_width, offset) }};
      {%- endfor %}
    {%- endfor %}

  {%- if registers|length > 0 %}
    {%- set printed = namespace(header = false) %}
    {%- for reg in registers %}
      {%- if reg.external %}
        {%- if not printed.header %}

  // Reset values for hwext registers and their fields for {{ interface.name|lower}} interface
        {%- set printed.header = true %}
        {%- endif %}
        {%- for offset in reg.offsets %}
          {%- set index = "_{}".format(loop.index0) if reg.offsets|length > 1 %}
          {%- set regname = (reg.name ~ index)|upper %}
  parameter logic {{ "[{}:0] {}_{}_RESVAL = {}'h {:x}".format(reg.msb, name|upper, regname, reg.msb + 1, reg.reset) }};
          {%- for field in reg.fields  %}
            {%- if 'reset' in field %}
  parameter logic {{ "[{}:0] {}_{}_{}{}_RESVAL = {}'h {:x}".format(field.width - 1, name|upper, regname, field.name|upper, index, field.width, field.reset) }};
            {%- endif -%}
          {%- endfor %}
        {%- endfor %}
      {%- endif -%}
    {% endfor %}
  {%- endif %}

  {%- if interface.windows|length > 0 %}

  // Window parameters for {{ interface.name|lower}} interface
    {%- for win in interface.windows  %}
  parameter logic [{{ addr_with_name }}-1:0] {{ name|upper }}_{{ win.name|upper }}_OFFSET = {{ "{}'h {:x}".format(interface.addr_width, win.offset) }};
  parameter int unsigned      {{ name|upper }}_{{ win.name|upper }}_SIZE   = 'h {{ "{:x}".format(win.size) }};
  parameter int unsigned      {{ name|upper }}_{{ win.name|upper }}_IDX    = {{ loop.index0 }};
    {%- endfor %}
  {%- endif %}

  {%- if registers|length > 0 %}

  // Register index for {{ interface.name|lower}} interface
  typedef enum int {
    {%- for reg in registers %}
      {%- set out_loop = loop %}
      {%- for offset in reg.offsets %}
        {%- set index = "_{}".format(loop.index0) if reg.offsets|length > 1 %}
        {%- set regname = (reg.name ~ index)|upper %}
    {{ "{}_{}{}".format(name, regname, "," if not (loop.last and out_loop.last) )|upper }}
      {%- endfor %}
    {%- endfor %}
  } {{ name }}{{interface_name}}_id_e;
  {%- endif %}

  {%- set ns = namespace(index=0) %}
  {%- set printed.header = false %}
    {%- for reg in registers %}
      {%- set out_loop = loop %}
      {%- for offset in reg.offsets %}
        {%- set regname = (reg.name ~ index)|upper %}
        {%- set index = "index[{num:>{width}}]".format(num=ns.index, width=num_regs_digits) %}
        {%- set suffix = "_{}".format(loop.index0) if reg.offsets|length > 1 %}
        {%- if not printed.header %}

  // Register width information to check illegal writes for {{ interface.name|lower}} interface
  parameter logic [3:0] {{ (name ~ interface_name)|upper }}_PERMIT [{{ interface.num_regs }}] = '{
          {%- set printed.header = true %}
        {%- endif %}
    4'b {{ "{:04b}{} // {} {}_{}{}".format(reg.opentitan.permit, "," if not (loop.last and out_loop.last) else " ", index, name|upper, regname, suffix) }}
        {%- set ns.index = ns.index + 1 %}
      {%- endfor %}
    {%- endfor %}
  {%- if printed.header %}
  };
  {%- endif %}
{%- endfor %}

endpackage
