# Manuel Eggimann <meggimann@iis.ee.ethz.ch>
#
# Copyright (C) 2021-2022 ETH Zürich
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from enum import Enum
from typing import Optional, Set, Dict, Union
from padrick.Model.Constants import SYSTEM_VERILOG_IDENTIFIER
from padrick.Model.SignalExpressionType import SignalExpressionType
from pydantic import BaseModel, constr, conint, validator, PrivateAttr, root_validator, Extra
from padrick.Model.TemplatedIdentifier import TemplatedIdentifierType
from padrick.Model.UserAttrs import UserAttrs
[docs]class PadSignalKind(str, Enum):
input = "input"
output = "output"
pad = "pad"
[docs]class SignalDirection(str, Enum):
soc2pads= "soc2pads"
pads2soc = "pads2soc"
bidir = "bidir"
[docs]class ConnectionType(str, Enum):
static = "static"
dynamic = "dynamic"
[docs]class Signal(BaseModel):
name: TemplatedIdentifierType
size: conint(ge=1, le=32) = 1
_direction: Optional[SignalDirection] = PrivateAttr(None)
def __init__(self, direction=None, *values, **kwargs):
super().__init__(*values, **kwargs)
self._direction = direction
def __eq__(self, other):
if isinstance(other, Signal):
return self.name == other.name and self.size == other.size and self.direction == other.direction
else:
raise NotImplemented
@property
def direction(self):
return self._direction
def __hash__(self):
return hash((self.name, self.size, self.direction))
[docs]class PadSignal(Signal):
description: Optional[str]
kind: PadSignalKind
conn_type: Optional[ConnectionType]
and_override_signal: SignalExpressionType = SignalExpressionType("")
or_override_signal: SignalExpressionType = SignalExpressionType("")
default_reset_value: Optional[int]
default_static_value: Optional[SignalExpressionType]
_static_signals: Set[Signal] = PrivateAttr(default=set())
user_attr: Optional[UserAttrs]
@property
def direction(self):
if self.kind == PadSignalKind.input:
return SignalDirection.soc2pads
elif self.kind == PadSignalKind.output:
return SignalDirection.pads2soc
else:
return SignalDirection.bidir
#pydantic model config
[docs] class Config:
extra = Extra.forbid
[docs] @root_validator(skip_on_failure=True)
def must_contain_conn_type_unsless_kind_pad(cls, values):
if values['kind'] != PadSignalKind.pad and not values['conn_type']:
raise ValueError("All Padsignals except the ones of kind 'pad' must contain a 'conn_type'")
return values
[docs] @root_validator(skip_on_failure=True)
def must_not_contain_default_value_if_landing_pad(cls, values):
if values['kind'] == PadSignalKind.pad:
if values.get('default_reset_value', None):
raise ValueError("Padsignals of kind 'pad' must not contain a default reset value.")
if values.get('default_static_value', None):
raise ValueError("Padsignals of kind 'pad' must not contain a default static value.")
return values
[docs] @root_validator(skip_on_failure=True)
def validate_output_pad(cls, values):
if values['kind'] == PadSignalKind.output:
if values.get('default_reset_value', None) != None:
raise ValueError("Padsignals of kind 'output' must not contain a reset value.")
if not values.get('default_static_value'):
values['default_static_value'] = SignalExpressionType("")
else:
if not values['default_static_value'].is_single_signal:
raise ValueError("Padsignals of kind 'output' must not have complex expression as "
"default_static_value. Only single signal identifiers or the empty expression is allowed.")
if not values['and_override_signal'].is_empty:
raise ValueError("Padsignals of kind 'output' must not have override signals.")
if not values['or_override_signal'].is_empty:
raise ValueError("Padsignals of kind 'output' must not have override signals.")
return values
@property
def static_signals(self):
static_signals = set()
if self.and_override_signal:
for signal_name in self.and_override_signal.signal_collection:
static_signals.add(Signal(signal_name, self.size))
if self.or_override_signal:
for signal_name in self.or_override_signal.signal_collection:
static_signals.add(Signal(signal_name, self.size))
if self.default_reset_value:
for signal_name in self.default_reset_value.signal_collection:
static_signals.add(Signal(signal_name, self.size))
if self.default_static_value:
for signal_name in self.default_static_value.signal_collection:
static_signals.add(Signal(signal_name, self.size))
return static_signals