-
Patrick Robbe authoredPatrick Robbe authored
fpga_comp.py 18.41 KiB
#!/usr/bin/python
"""
fpga_comp.py -- module to query and set registers managed by the fpga
Note:
This code will be running on FC
Author
PYD 07/12/2017
JPC 25/10/2018 : added fpga version read
"""
import time
import json
from lli import mem_multi as mem
class Arria10(object):
""" Class to manage registers of the arria10.
The mapping of port registers per type of PLL is given as a class dictionnary
of lists of registers addresses.
Args:
dev (int):
"""
regs = {"SI5344_U54": {
0:0x000,
1: 0x160},
"SI5345_U23": {
0: 0x30,
1: 0x40,
2: 0x50,
3: 0x60},
"SI5345_U48": {
0: 0x70,
1: 0x80,
3: 0x90,
4: 0xA0,
8: 0x130},
"SI53344": {
0: 0xB0,
1: 0xC0,
2: 0xD0,
3: 0xE0,
4: 0xF0,
5: 0x100,
6: 0x110,
7: 0x120,
8: 0x150},
"SI5340": {
0: 0x140}
}
clk_meas = 0x01000 # offset on avalon bus
io_pll = 0x40000
list_adr_pll = [0x00088000, 0x00098000, 0x000A8000, 0x000B8000, 0x000C8000, 0x000D8000, 0x000E8000, 0x000F8000, 0x00070000]
def __init__(self, dev):
"""
Args:
dev (int): board identifier
type_pll forced to fPLL
"""
self.dev = dev
self.type_pll = 0
def dump_pll_frequencies(self, source):
"""dump the frequency measure for all ports of the given PLL.
Args:
source (str):
name of the PLL. Possible values are SI5344_U54,
SI5345_U23, SI5345_U48, SI53344, SI53340.
Raises:
ValueError:
for invalid name.
"""
if source not in Arria10.regs:
raise ValueError("unknown source")
fmt = "{}_{} register 0x{:x} status {} value 0x{:x} [{}]"
for port, reg in Arria10.regs[source].iteritems():
val = mem.read(self.dev, Arria10.clk_meas + reg)
print fmt.format(source, port, reg, val[0], val[1], val[1])
def read_pll_port_frequency(self, source, port):
"""Measure the frequency on the given ports of the PLL.
Args:
source (str):
name of the PLL. Possible values are SI5344_U54,
SI5345_U23, SI5345_U48, SI53344, SI53340.
port (int)
a number ranging from 0 to 8.
Available port depends on the PLL.
Return
tuple:
status and value
Raises:
ValueError:
for invalid name of port
"""
if source not in Arria10.regs:
raise ValueError("unknown source {}".format(source))
ports = Arria10.regs[source]
if port not in ports:
raise ValueError("unkown port {}".format(port))
return mem.read(self.dev, Arria10.clk_meas + ports[port])
def temperature(self):
""" Return the internal temperature of the FPGA.
Returns
tuple:
status, value
"""
add = Arria10.clk_meas + 0x150
return mem.read(self.dev, add)
def clear_reset_gbt(self):
""" Sets the system_status_register to "00000001"
in order to clear the reset signal feeding the
serial transceivers.
Returns
status
"""
value = 0x1
add = 0x30120
# print "..... GBT active"
return mem.write(self.dev, add, value)
def init_reset_gbt(self):
""" Sets the system_status_register to "00000000"
in order to clear the reset signal feeding the
serial transceivers.
Returns
status
"""
value = 0x0
add = 0x30120
print "..... GBT in reset"
return mem.write(self.dev, add, value)
def reconfig_pll(self, num_pll):
"""reconfigure the given PLL.
Args:
PLL number
Raises:
ValueError:
for invalid name.
"""
if num_pll > 8:
#print "NUM PLL FORBIDDEN"
return False
pll_add = self.list_adr_pll[num_pll]
timeout = time.time() + 2 # timeout = 2 second
#### patch PLL direct mode ON
#print ".patch PLL direct mode ON "
status, val = mem.read(self.dev, pll_add + 0x126*4)
#print val
new_val = val|0x01
# print new_val
mem.write(self.dev, pll_add + 0x126*4, new_val)
# print "********* Start calibration PLL" + str(num_pll) + " *********"
#### 1
#print ". request user acces "
mem.write(self.dev, pll_add+0x000*4, 0x2) # write 0x2
#### 2
# print ". wait for reconfig_waitrequest to be deasserted "
bool_wait0 = True
while bool_wait0:
status, val = mem.read(self.dev, pll_add+0x280*4)
test_bit = val&0x04
if test_bit == 0:
bool_wait0 = False
# print ". bus granted to user"
else:
if time.time() > timeout:
# print "********** TIMEOUT **********"
return False
#### 3
# print ". start calibration PLL "
status, val = mem.read(self.dev, pll_add + 0x100*4)
if self.type_pll == 0:
new_val = val|0x2 # FPLL PLL
# print ". Targetting PLL type = FPLL"
if self.type_pll == 1:
new_val = val|0x1 # ATX PLL
# print ". Targetting PLL type = ATX"
mem.write(self.dev, pll_add + 0x100*4, new_val)
#### 4
# print ". release bus to preSICE"
mem.write(self.dev, pll_add +0x000*4, 0x1)
#### 5
# print ". check reset of call_busy signal"
bool_call_busy1 = True
while bool_call_busy1:
status, val = mem.read(self.dev, pll_add +0x280*4)
test_bit = val&0x02
if test_bit == 0:
bool_call_busy1 = False
print "PLL" + str(num_pll) + " Calibration done "
else:
if time.time() > timeout:
print "PLL" + str(num_pll) + " TIMEOUT during calibration"
return False
### patch PLL direct mode OFF
#print ".patch PLL direct mode OFF "
status, val = mem.read(self.dev, pll_add + 0x126*4)
#print val
new_val = val&0xfe
#print new_val
mem.write(self.dev, pll_add + 0x126*4, new_val)
### check pll is locked
(status, message) = self.status_pll(num_pll)
return (status, message)
############ status_pll return False,"" return True,"" ####################
def status_pll(self, num_pll):
"""
return status PLL
"""
if num_pll > 8:
#print "NUM PLL FORBIDDEN"
return False, ""
pll_add = self.list_adr_pll[num_pll]
check_lock = False
timeout = time.time() + 2 # timeout = 2 second
#### Test PLL locked
# print ". check PLL" + str(num_pll) + " lock status"
bool_call_busy2 = True
while bool_call_busy2:
status, val = mem.read(self.dev, pll_add + 0x280*4)#0x280
test_bit = val&0x01
if test_bit == 1:
bool_call_busy2 = False
print " PLL" + str(num_pll) + " is locked"
check_lock = True
#print
#print
return check_lock, "PLL" + str(num_pll) + " is locked" #renvoie 1 pour valider la Qprossbar + message
else:
if time.time() > timeout:
print "********** PLL" + str(num_pll) + " TIMEOUT **********"
#print
#print
return False, "PLL" + str(num_pll) + " is not locked :timeout"
# return True, ""
def dump_pll_registers(self):
"""dump the io_pll registers
Args:
source ():
no name
Raises:
ValueError:
for invalid name.
"""
reg_address = {
"m": 0x90,
"n": 0xa0,
"c0": 0xc0,
"c1": 0xc1,
"c2": 0xc2,
"c3": 0xc3,
"c4": 0xc4,
"c5": 0xc5,
"c6": 0xc6,
"c7": 0xc7,
"c8": 0xc8
}
print
print "== Reading iopll registers =="
print "Input frequency = 100 MHz"
status, val = mem.read(self.dev, Arria10.io_pll + 4 * reg_address["m"])
if val & 0x10000 == 0:
msb = val & 0xFF
lsb = val >> 8 & 0xFF
m = msb + lsb
else:
m = 1
print "multiplier m = ", m
status, val = mem.read(self.dev, Arria10.io_pll + 4 * reg_address["n"])
if val & 0x10000 == 0:
msb = val & 0xFF
lsb = val >> 8 & 0xFF
n = msb + lsb
else:
n = 1
print "divider n = ", n
#for reg in ("c0", "c1", "c2", "c3", "c4", "c5", "c6", "c7"):
# status, val = mem.read(self.dev, Arria10.io_pll + 4 * reg_address[reg])
# if val & 0x10000 == 0:
# msb = val & 0xFF
# lsb = val >> 8 & 0xFF
# divider = msb + lsb
# else:
# divider = 1
# print "divider ", reg, "= ", divider, ", frequency = ", 100*m/n/divider, " MHz"
reg = "c0"
status, val = mem.read(self.dev, Arria10.io_pll + 4 * reg_address[reg])
if val & 0x10000 == 0:
msb = val & 0xFF
lsb = val >> 8 & 0xFF
divider = msb + lsb
else:
divider = 1
print "divider ", reg, "= ", divider, ", frequency = ", 100*m/n/divider, " MHz"
def change_pll_ratio(self, frequency):
reg_address = {
"m": 0x90,
"n": 0xa0,
"c0": 0xc0,
"c1": 0xc1,
"c2": 0xc2,
"c3": 0xc3,
"c4": 0xc4,
"c5": 0xc5,
"c6": 0xc6,
"c7": 0xc7,
"c8": 0xc8
}
print
print "== Changing frequency on c0"
m = 0x1818
n = 0x0203
if frequency == 10 : div = 0x3030
elif frequency == 20 : div = 0x1818
elif frequency == 40 : div = 0x0C0C
elif frequency == 80 : div = 0x0606
elif frequency == 160 : div = 0x0303
elif frequency == 240 : div = 0x0202
elif frequency == 480 : div = 0x0101
elif frequency == 560 :
m = 0x1C1C
div = 0x0101
elif frequency == 600 :
m = 0x0606
div = 0x0101
n = 0x10000
elif frequency == 620 :
m = 0x1F1F
div = 0x0101
elif frequency == 630 :
m = 0x201F
div = 0x0101
elif frequency == 635 :
m = 0x403F
div = 0x0101
n = 0x0505
elif frequency == 640 :
m = 0x1010
div = 0x10000
else :
div = 0x3030
print "Wrong value: autorized values are 10, 20, 40, 80, 160, 240, 480, 560, 600, 620, 630, 635, 640"
print "Returning to 10 MHz"
mem.write(self.dev, Arria10.io_pll + 4 * reg_address["m"], m)
mem.write(self.dev, Arria10.io_pll + 4 * reg_address["n"], n)
mem.write(self.dev, Arria10.io_pll + 4 * reg_address["c0"], div)
print "empty FIFO"
mem.write(self.dev, Arria10.io_pll + 4 * 0, 0) # write anything in 0 to empty the FIFO
print
def set_tx_dis(self):
mem.write(self.dev, 0x20040, 0x3)
status, val = mem.read(self.dev,0x20040)
return val
def reset_tx_dis(self):
mem.write(self.dev, 0x20040, 0x0)
status, val = mem.read(self.dev,0x20040)
return val
def write_pattern_ctrl_reg(self, pattern):
mem.write (self.dev, 0x30010, pattern)
status, val = mem.read (self.dev, 0x30010)
return hex(val)
def clear_gbt_rx_ready_lost_flag(self):
status, val = mem.read (self.dev, 0x30010)
val = val | 0x08 # set bit
mem.write (self.dev, 0x30010, val)
val = val & 0xF7 # clear bit
mem.write (self.dev, 0x30010, val)
def clear_error_seen_flag(self):
status, val = mem.read (self.dev, 0x30010)
val = val | 0x04 # set bit
mem.write (self.dev, 0x30010, val)
val = val & 0xFB # clear bit
mem.write (self.dev, 0x30010, val)
def read_ready_lost_flag(self, num_phy, channel):
"""
Read rx_ready lost flag
Args:
num_phy : phy number
channel : channel number
Return:
read_value : 1 for ready lost, else 0
"""
mask = 1 << (16 + channel)
return self.read_mask(0x30020 + 0x10 * num_phy, mask)
def read_error_seen_flag(self, num_phy, channel):
"""
Read error seen flag
Args:
num_phy : phy number
channel : channel number
Return:
read_value : 1 for ready lost, else 0
"""
mask = 1 << (0 + channel)
return self.read_mask (0x30020 + 0x10 * num_phy, mask)
def read_widebus_error_seen_flag(self, num_phy, channel):
"""
Read widebus error seen flag
Args:
num_phy : phy number
channel : channel number
Return:
read_value : 1 for ready lost, else 0
"""
mask = 1 << (8 + channel)
return self.read_mask (0x30020 + 0x10 * num_phy, mask)
def read_rx_ready(self, num_phy, channel):
"""
Read rx_ready flag
Args:
num_phy : phy number
channel : channel number
Return:
read_value : 1 for ready, 0 for not ready
"""
mask = 1 << (22 + channel)
return self.read_mask(0x30020 + 0x10 * num_phy, mask)
def read_mask(self, reg, mask):
"""
Read a register with a mask
Args:
reg : register address
mask : each bit set to 1 is read, other are ignored
Return:
read_value : read value with mask and align right
"""
status, val = mem.read(self.dev, reg)
masked_data = val & mask
while mask & 1 == 0 :
masked_data = masked_data >> 1
mask = mask >> 1
return hex(masked_data)
def read_version(self):
"""
Read fpga version
Return:
read_value : read value with mask and align right
"""
base_address = 0x0000
word = 0
char = ""
string = ""
status, val = mem.read(self.dev, base_address + 0)
if chr(val) == "{":
while char != "}":
status, val = mem.read(self.dev, base_address + 4 * word)
word += 1
char = chr(val)
string += char
else:
string = "{\"design_version\" : \"not implemented\"}"
return json.loads(string)
def runNumber(self):
status, val = mem.read( self.dev , 0x00050020 )
return ( val & 0xFF00 ) >> 8 | ( val & 0x00FF ) << 8
def triggerTag(self):
status, val = mem.read( self.dev , 0x00050040 )
return ( val & 0xFF00 ) >> 8 | ( val & 0x00FF ) << 8
def clockUp(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x800 ) >> 11
def ttdUp(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x1000 ) >> 12
def triggerType(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x1E000 ) >> 13
def triggerCounter(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x1FFE0000 ) >> 17
def rxReady(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x1 ) >> 0
def rxReadyIndividual(self, i):
status, val = mem.read( self.dev , 0x00050060 )
return ( val & ( 0x1 << i ) ) >> i
def txReady(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x2 ) >> 1
def txReadyIndividual(self, i):
status, val = mem.read( self.dev , 0x00050060 )
return ( val & ( 0x10 << i ) ) >> ( i + 4 )
def b2linkReady(self):
status, val = mem.read( self.dev , 0x00050000 )
return ( val & 0x4 ) >> 2
def b2linkReadyIndividual(self, i):
status, val1 = mem.read( self.dev , 0x000500C0 )
status, val2 = mem.read( self.dev , 0x000500E0 )
return ( ( ( val1 & ( 0x1 << i ) ) >> i ) & ( ( val2 & ( 0x1 << i ) ) >> i ) )
def resynchronizeLink(self, i ):
mem.write( self.dev , 0x00050240 , 0x0 )
mem.write( self.dev , 0x00050240 , 0x1 << i )
mem.write( self.dev , 0x00050240 , 0x0 )
def resetTriggerCounter(self):
mem.write( self.dev , 0x00050100 , 0x0 )
mem.write( self.dev , 0x00050100 , 0x2 )
mem.write( self.dev , 0x00050100 , 0x0 )
def main():
""" Main function
instanciation of Class Si534x()
execute hard test for all PLLs
"""
fpga = Arria10(0)
#init LLI reg
fpga.init_reset_gbt()
plls = ["SI5344_U54", "SI5345_U23", "SI5345_U48", "SI53344", "SI5340"]
for pll in plls:
fpga.dump_pll_frequencies(pll)
fpga.temperature()
fpga.read_pll_port_frequency("SI5344_U54", 0)
fpga.read_pll_port_frequency("SI5344_U54", 1)
fpga.read_pll_port_frequency("SI5340", 0)
#
#
#
# print "PLL calibration"
# for i in range (0, 8):
# fpga.reconfig_pll(i)
#
#
# fpga.dump_pll_registers()
# fpga.change_pll_ratio(10)
# fpga.dump_pll_registers()
# status, temperature = fpga.temperature()
# print "Temperature = ", temperature """
# print "Clearing reset for transceivers"
# fpga.clear_reset_gbt()
print fpga.read_rx_ready (0, 0)
print fpga.read_rx_ready (0, 1)
print fpga.read_rx_ready (0, 2)
print fpga.read_rx_ready (0, 3)
print fpga.read_rx_ready (0, 4)
print fpga.read_rx_ready (0, 5)
if __name__ == "__main__":
main()