@@ -15,6 +15,7 @@ import re
1515from pathlib import Path
1616from collections import defaultdict
1717
18+
1819def getDefineForDevice (device_id , familyDefines ):
1920 """
2021 Returns the STM32 specific define from an identifier
@@ -61,45 +62,67 @@ def getDefineForDevice(device_id, familyDefines):
6162
6263 return None
6364
65+
66+ class RegisterMap :
67+ def __init__ (self , registers , logger ):
68+ self ._registers = registers
69+ self ._register_string = "\n " .join (registers )
70+ self .result = None
71+ self ._log = logger
72+ # print(self._register_string)
73+
74+ def _result (self , query , value , ll ):
75+ self .result = value
76+ self ._log (f"{ query } -{ ll } -> { self .result } " )
77+ return self .result
78+
79+ def findall (self , query , default = None ):
80+ if query in self ._registers :
81+ return self ._result (query , [query ], "fi" )
82+ if matches := re .findall (f"(?:{ query } )\n " , self ._register_string ):
83+ return self ._result (query , matches , "fn" )
84+ return self ._result (query , default or [], "fd" )
85+
86+ def search (self , query , default = None ):
87+ if query in self ._registers :
88+ return self ._result (query , query , "si" )
89+ if (match := re .search (f"(?:{ query } )\n " , self ._register_string )) is not None :
90+ if not (groups := match .groups ()):
91+ return self ._result (query , match .group (0 )[:- 1 ], "s0" )
92+ if len (groups ) == 1 :
93+ return self ._result (query , groups [0 ], "s1" )
94+ return self ._result (query , groups , "sn" )
95+ return self ._result (query , default , "sd" )
96+
97+ def _ops (self , re_pers , re_regs , re_bits , bit_fmt ):
98+ reg_bits = defaultdict (list )
99+ matches = re .findall (f"(({ re_pers } )_({ re_regs } )_(?:{ re_bits } ))\n " , self ._register_string )
100+ for whole , per , reg in matches :
101+ reg_bits [f"{ per } ->{ reg } " ].append (whole )
102+ statements = [f"{ reg } { bit_fmt (' | ' .join (bits ))} ;" for reg , bits in reg_bits .items ()]
103+ return "\n " .join (statements )
104+
105+ def set (self , pers , regs , bits ):
106+ return self ._ops (pers , regs , bits , lambda bits : f" |= { bits } " )
107+
108+ def clear (self , pers , regs , bits ):
109+ return self ._ops (pers , regs , bits , lambda bits : f" &= ~({ bits } )" )
110+
111+
64112bprops = {}
65- def common_rcc_map (env ):
113+ def common_register_map (env ):
66114 """
67- Finds all CMSIS bit fields related to enabling and resetting peripherals
68- in the RCC of the format `RCC_(REGISTER)_(PERIPHERAL)_(TYPE)` where:
115+ Finds all register and bit names in the CMSIS header file.
69116
70- - REGISTER: a variation of `(BUS)(ID?)(ENR|RSTR)`, e.g. `AHB1ENR`
71- - PERIPHERAL: typical peripheral name, e.g. `GPIOA`
72- - TYPE: either `EN` or `RST`.
73-
74- :returns: a 2D-dictionary: `map[PERIPHERAL][TYPE] = REGISTER`
117+ :returns: a RegisterMap object that allows regex-ing for register names.
75118 """
76- headers = env .query ("headers" )
77- core_header = repopath ("ext/arm/cmsis/CMSIS/Core/Include" , headers ["core_header" ])
78-
79- content = ""
80- for header_path in [core_header , localpath (bprops ["folder" ], headers ["device_header" ])]:
81- content += Path (header_path ).read_text (encoding = "utf-8" , errors = "replace" )
82-
83- # find mpu and fpu features
84- features = re .findall (r"#define +__([MF]PU)_PRESENT +([01])" , content )
85- core_features = {f [0 ]:bool (int (f [1 ])) for f in features }
86- # find all peripherals
87- mperipherals = re .findall (r"#define +(.*?) +\(\((.*?_Type(?:Def)?)" , content )
88- # We only care about the absolute peripheral addresses
89- peripherals = [(p [0 ],p [1 ]) for p in mperipherals ]
90- # filter out MPU and/or FPU if required
91- peripherals = filter (lambda p : p [0 ] not in core_features or core_features [p [0 ]], peripherals )
92- peripherals = sorted (peripherals , key = lambda p : p [0 ])
93- # print("\n".join([s+" -> "+hex(a) for (s,k,a) in peripherals]))
94-
95- # Find all RCC enable and reset definitions
96- match = re .findall (r"RCC_([A-Z0-9]*?)_([A-Z0-9]+?)(EN|RST) " , content )
97- rcc_map = defaultdict (dict )
98- for (reg , per , typ ) in match :
99- rcc_map [per ][typ ] = reg
100-
101- bprops ["peripherals" ] = peripherals
102- return rcc_map
119+ headers = env .query (":cmsis:device:headers" )
120+ core_header = Path (repopath ("ext/arm/cmsis/CMSIS/Core/Include" , headers ["core_header" ]))
121+ device_header = Path (localpath (bprops ["folder" ], headers ["device_header" ]))
122+ content = "\n " .join (header .read_text (encoding = "utf-8" , errors = "replace" )
123+ for header in [core_header , device_header ])
124+ registers = re .findall (r"#define\s+([^\s\(\)]*?)(?:_Msk\s+\(|\s+\(.*?_Pos\)|\s+\(?0x)" , content )
125+ return RegisterMap (registers , print )
103126
104127
105128def common_header_file (env ):
@@ -127,7 +150,7 @@ def common_header_file(env):
127150 define = None
128151
129152 content = Path (localpath (folder , family_header )).read_text (encoding = "utf-8" , errors = "replace" )
130- match = re .findall (r"if defined\((?P<define> STM32[CFGHLU ][\w\d]+)\)" , content )
153+ match = re .findall (r"if defined\((STM32[A-Z ][\w\d]+)\)" , content )
131154 define = getDefineForDevice (device .identifier , match )
132155 if define is None or match is None :
133156 raise ValidateException ("No device define found for '{}'!" .format (device .partname ))
@@ -198,17 +221,17 @@ def prepare(module, options):
198221 return False
199222
200223 module .add_query (
201- EnvironmentQuery (name = "rcc-map " , factory = common_rcc_map ))
224+ EnvironmentQuery (name = "headers " , factory = common_header_file ))
202225 module .add_query (
203226 EnvironmentQuery (name = "peripherals" , factory = common_peripherals ))
204227 module .add_query (
205- EnvironmentQuery (name = "headers " , factory = common_header_file ))
228+ EnvironmentQuery (name = "registers " , factory = common_register_map ))
206229
207230 module .depends (":cmsis:core" )
208231 return True
209232
210233def validate (env ):
211- env .query ("rcc-map " )
234+ env .query ("headers " )
212235 env .query ("peripherals" )
213236
214237def build (env ):
0 commit comments