| # Copyright lowRISC contributors. |
| # Licensed under the Apache License, Version 2.0, see LICENSE for details. |
| # SPDX-License-Identifier: Apache-2.0 |
| |
| from typing import List |
| |
| from serialize.parse_helpers import check_keys, check_str, check_int |
| |
| |
| class LSUDesc: |
| '''Represents the "lsu" field for an instruction in the YAML ISA. |
| |
| This has a type (mem-load, mem-store, csr or wsr), a list of operands whose |
| values are summed to get the address or index that's loaded and possibly a |
| 'bytes' value: the number of addresses touched by the operation. |
| |
| ''' |
| |
| TYPES = ['mem-load', 'mem-store', 'csr', 'wsr-load', 'wsr-store'] |
| |
| def __init__(self, |
| lsu_type: str, |
| target: List[str], |
| idx_width: int) -> None: |
| |
| assert lsu_type in LSUDesc.TYPES |
| |
| self.lsu_type = lsu_type |
| self.target = target |
| # idx_width is the number of addresses/indices touched by the |
| # operation. For a memory, this is measured in bytes. For a csr/wsr |
| # operation, this is always 1 (one register). |
| self.idx_width = idx_width |
| |
| @staticmethod |
| def from_yaml(yml: object, what: str) -> 'LSUDesc': |
| yd = check_keys(yml, what, ['type', 'target'], ['bytes']) |
| |
| type_what = 'type field for ' + what |
| lsu_type = check_str(yd['type'], type_what) |
| if lsu_type not in LSUDesc.TYPES: |
| raise ValueError('{} is {!r}, but should be one ' |
| 'of the following: {}.' |
| .format(type_what, lsu_type, |
| ', '.join(repr(t) |
| for t in LSUDesc.TYPES))) |
| |
| target = yd['target'] |
| if isinstance(target, str): |
| target_parts = [target] |
| else: |
| target_parts = [] |
| if not isinstance(target, list): |
| raise ValueError('target field for {} should be a string or a ' |
| 'list of strings, but actually has type {}.' |
| .format(what, type(target).__name__)) |
| for idx, part in enumerate(target): |
| elt_what = ('element {} of the target list for {}' |
| .format(idx, what)) |
| target_parts.append(check_str(part, elt_what)) |
| |
| if lsu_type.startswith('mem-'): |
| if 'bytes' not in yd: |
| raise ValueError('{} defines a memory operation, so requires ' |
| 'a bytes field (how many bytes does this touch?)' |
| .format(what)) |
| idx_width = check_int(yd['bytes'], 'bytes field for ' + what) |
| else: |
| if 'bytes' in yd: |
| raise ValueError("{} isn't a memory operation, so cannot have " |
| "a bytes field." |
| .format(what)) |
| idx_width = 1 |
| |
| return LSUDesc(lsu_type, target_parts, idx_width) |