# # Copyright 2010 Ettus Research LLC # # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see . # import re import sys import math from Cheetah.Template import Template COMMON_TMPL = """\ #import time /*********************************************************************** * This file was generated by $file on $time.strftime("%c") **********************************************************************/ \#ifndef INCLUDED_$(name.upper())_HPP \#define INCLUDED_$(name.upper())_HPP \#include \#include \#include \#include class $(name)_t{ public: #for $reg in $regs #if $reg.get_enums() enum $reg.get_type(){ #for $i, $enum in enumerate($reg.get_enums()) #set $end_comma = ',' if $i < len($reg.get_enums())-1 else '' $(reg.get_name().upper())_$(enum[0].upper()) = $enum[1]$end_comma #end for }; #end if $reg.get_type() $reg.get_name(); #end for $(name)_t(void){ _state = NULL; #for $reg in $regs $reg.get_name() = $reg.get_default(); #end for } ~$(name)_t(void){ delete _state; } $body void save_state(void){ if (_state == NULL) _state = new $(name)_t(); #for $reg in $regs _state->$reg.get_name() = this->$reg.get_name(); #end for } template std::set get_changed_addrs(void){ if (_state == NULL) throw std::runtime_error("no saved state"); //check each register for changes std::set addrs; #for $reg in $regs if(_state->$reg.get_name() != this->$reg.get_name()){ addrs.insert($reg.get_addr()); } #end for return addrs; } private: $(name)_t *_state; }; \#endif /* INCLUDED_$(name.upper())_HPP */ """ def parse_tmpl(_tmpl_text, **kwargs): return str(Template(_tmpl_text, kwargs)) def to_num(arg): return eval(arg) class reg: def __init__(self, reg_des): try: self.parse(reg_des) except Exception, e: raise Exception, 'Error parsing register description: "%s"\nWhat: %s'%(reg_des, e) def parse(self, reg_des): x = re.match('^(\w*)\s*(\w*)\[(.*)\]\s*(\w*)\s*(.*)$', reg_des) name, addr, bit_range, default, enums = x.groups() #store variables self._name = name self._addr = to_num(addr) if ':' in bit_range: self._addr_spec = sorted(map(int, bit_range.split(':'))) else: self._addr_spec = int(bit_range), int(bit_range) self._default = to_num(default) #extract enum self._enums = list() if enums: enum_val = 0 for enum_str in map(str.strip, enums.split(',')): if '=' in enum_str: enum_name, enum_val = enum_str.split('=') enum_val = to_num(enum_val) else: enum_name = enum_str self._enums.append((enum_name, enum_val)) enum_val += 1 def get_addr(self): return self._addr def get_enums(self): return self._enums def get_name(self): return self._name def get_default(self): for key, val in self.get_enums(): if val == self._default: return str.upper('%s_%s'%(self.get_name(), key)) return self._default def get_type(self): if self.get_enums(): return '%s_t'%self.get_name() return 'boost::uint%d_t'%max(2**math.ceil(math.log(self.get_bit_width(), 2)), 8) def get_shift(self): return self._addr_spec[0] def get_mask(self): return hex(int('1'*self.get_bit_width(), 2)) def get_bit_width(self): return self._addr_spec[1] - self._addr_spec[0] + 1 def generate(name, regs_tmpl, body_tmpl='', file=__file__): regs = map(reg, parse_tmpl(regs_tmpl).splitlines()) body = parse_tmpl(body_tmpl, regs=regs).replace('\n', '\n ').strip() code = parse_tmpl(COMMON_TMPL, name=name, regs=regs, body=body, file=file, ) open(sys.argv[1], 'w').write(code)