1#!/usr/bin/env python3 2# -*- coding: utf-8 -*- 3# 4# Copyright (C) 2024 Antmicro 5# 6# Licensed under the Apache License, Version 2.0 (the "License"); 7# you may not use this file except in compliance with the License. 8# You may obtain a copy of the License at 9# 10# http://www.apache.org/licenses/LICENSE-2.0 11# 12# Unless required by applicable law or agreed to in writing, software 13# distributed under the License is distributed on an "AS IS" BASIS, 14# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15# See the License for the specific language governing permissions and 16# limitations under the License. 17# 18# SPDX-License-Identifier: Apache-2.0 19 20from systemrdl.node import FieldNode, MemNode, RegNode, AddrmapNode 21from systemrdl.walker import RDLListener, RDLWalker, WalkerAction 22 23from .csharp import ast as ast 24from .memory import RegArray 25 26 27class ScannedState: 28 def __init__(self, peripheral_name: str, 29 registers: list[RegNode], 30 register_arrays: list[RegArray], 31 resets: dict[RegNode, int]): 32 self.top_name = peripheral_name 33 self.registers = registers 34 self.register_arrays = register_arrays 35 self.resets = resets 36 37class RdlDesignScanner(RDLListener): 38 regs: list[RegNode] 39 reg_arrs: list[RegArray] 40 resets: dict[str, int] 41 peripheral_name: str 42 array: None | tuple[str, int] 43 mem: None | tuple[str, int] 44 45 def __init__(self, top_node: AddrmapNode) -> None: 46 self.top_node = top_node 47 self.regs = [] 48 self.reg_arrs = [] 49 self.mem = None 50 self.array = None 51 self.resets = {} 52 self.peripheral_name = top_node.inst_name 53 54 def run(self) -> ScannedState: 55 RDLWalker().walk(self.top_node, self) 56 return ScannedState(self.peripheral_name, self.regs, self.reg_arrs, self.resets) 57 58 def enter_Reg(self, node: RegNode) -> WalkerAction | None: 59 match self.mem: 60 case None: 61 self.regs.append(node) 62 case (str() as mem_name, addr): 63 if node.is_array: 64 if len(node.array_dimensions) != 1: 65 raise RuntimeError('Multidimensional arrays are unsupported') 66 reg_array = RegArray(mem_name, node, addr) 67 self.reg_arrs.append(reg_array) 68 69 self.resets[node.inst_name] = 0 70 return WalkerAction.Continue 71 72 def enter_Field(self, node: FieldNode) -> WalkerAction | None: 73 reset = node.get_property('reset') 74 self.add_field_reset_value(node, reset if reset is not None else 0) 75 return WalkerAction.Continue 76 77 def enter_Mem(self, node: MemNode) -> WalkerAction | None: 78 if self.mem is not None: 79 raise RuntimeError('Encountered a nested memory') 80 81 self.mem = (node.inst_name, node.absolute_address) 82 83 return WalkerAction.Continue 84 85 def exit_Mem(self, node: MemNode) -> WalkerAction | None: 86 self.mem = None 87 return WalkerAction.Continue 88 89 def add_field_reset_value(self, node: FieldNode, reset: int) -> None: 90 if reset == 0: 91 return 92 93 width = node.high - node.low + 1 94 fullreset = (1 << width) - 1; 95 96 self.resets[self.regs[-1].inst_name] |= fullreset << node.low