#
# 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)