#!/usr/bin/python

# Copyright CERN, 2011
# Author: Matthieu Cattin (CERN)
# Licence: GPL v2 or later.
# Website: http://www.ohwr.org
# Last modifications: 27/4/2012

# Import standard modules
import sys
import time

# Import specific modules


# Class to access 32-bit wishbone registers on BAR0

class CSRDeviceOperationError(Exception):
    def __init__(self, addr, reg_map, msg):
        self.msg = msg
        self.addr = addr
        self.reg_map = reg_map
    def __str__(self):
        return ("CSR [Wishbone core base address:0x%08X (%s)]: %s" %(self.addr, self.reg_map[0], self.msg))

class CCSR:

	def __init__(self, bus, base_addr, reg_map=None):
		self.base_addr = base_addr
		self.bus = bus
                self.reg_map = reg_map

        ###########################################################################
        # The following functions accesses registers with the address offset only,
        # the register map is not used.

	def wr_reg(self, addr, val):
		#print '[CSR] wr:%.8X reg:%.8X' % (val,(self.base_addr+addr))
		self.bus.iwrite(0, self.base_addr +  addr, 4, val)


	def rd_reg(self, addr):
		reg = self.bus.iread(0, self.base_addr + addr, 4)
		#print '[CSR] reg:%.8X value:%.8X' % ((self.base_addr+addr), reg)
		return reg


	def wr_bit(self, addr, bit, value):
		reg = self.rd_reg(addr)
		if(0==value):
			reg &= ~(1<<bit)
		else:
			reg |= (1<<bit)
		self.wr_reg(addr, reg)


	def rd_bit(self, addr, bit):
		if(self.rd_reg(addr) & (1<<bit)):
			return 1
		else:
			return 0

        ###########################################################################
        # The following functions are based on the register map
        # This file is stored in an external file and might be generated by wbgen

        # Get register's field value
        def get_field(self, reg, field):
            if(reg in self.reg_map[1]): # test if register exist in register map
                if(field in self.reg_map[1][reg][2]): # test if field exist in register

                    reg_addr = self.reg_map[1][reg][0]
                    field_mask = self.reg_map[1][reg][2][field][2]
                    field_offset = self.reg_map[1][reg][2][field][0]

                    reg_val = self.rd_reg(reg_addr)
                    reg_val = (field_mask & (reg_val >> field_offset))
                    return reg_val
                else:
                    raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested field (%s) doesn\'t exist.'%field)
            else:
                raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested register (%s) doesn\'t exist.'%reg)


        # Set register's field value
        def set_field(self, reg, field, value):
            if(reg in self.reg_map[1]): # test if register exist in register map
                if(field in self.reg_map[1][reg][2]): # test if field exist in register

                    reg_addr = self.reg_map[1][reg][0]
                    field_mask = self.reg_map[1][reg][2][field][2]
                    field_offset = self.reg_map[1][reg][2][field][0]

                    reg_val = self.rd_reg(reg_addr)
                    reg_val &= ~(field_mask << field_offset)
                    reg_val |= ((field_mask & value) << field_offset)
                    self.wr_reg(reg_addr, reg_val)
                    return reg_val
                else:
                    raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested field (%s) doesn\'t exist.'%field)
            else:
                raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested register (%s) doesn\'t exist.'%reg)


        # Get register value
        def get_reg(self, reg):
            if(reg in self.reg_map[1]): # test if register exist in register map
                return self.rd_reg(self.reg_map[1][reg][0])
            else:
                raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested register (%s) doesn\'t exist.'%reg)

        # Set register value
        def set_reg(self, reg, value):
            if(reg in self.reg_map[1]): # test if register exist in register map
                self.wr_reg(self.reg_map[1][reg][0], value)
            else:
                raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested register (%s) doesn\'t exist.'%reg)

        # Print all register map
        def print_reg_map(self):
            print "\n%s:" % (self.reg_map[0])
            print "--------------------------------------------------"
            # loop over registers and sort them by address offset
            for reg in sorted(self.reg_map[1].iteritems(), key=lambda (k,v): v[0]):
                value = self.get_reg(reg[0])
                print " * %-50s:0x%08X (%d)" % (reg[1][1],value, value)
                # loop over fields and sort them by position
                for field in sorted(reg[1][2].iteritems(), key=lambda (k,v): v[0]):
                    value = self.get_field(reg[0], field[0])
                    print "   - %-48s:0x%X (%d)" % (field[1][1],value, value)
                if(len(reg[1][2]) != 0):
                    print ''

        def get_reg_addr(self, reg):
            if(reg in self.reg_map[1]): # test if register exist in register map
                return self.reg_map[1][reg][0]
            else:
                raise CSRDeviceOperationError(self.base_addr, self.reg_map, 'Requested register (%s) doesn\'t exist.'%reg)
