Маска и изменение 8-байтового сигнала от последовательной связи FPGA - PullRequest
0 голосов
/ 14 апреля 2020

Я борюсь с созданием маски, чтобы записывать только определенные биты моих данных. В настоящее время я читаю 32-битные данные по серийному. После прочтения я получаю следующую информацию:

b'rt 00000000\n'

Это имеет тип байтов. Я предполагаю, что мои 32 бита из определенного регистра конвертируются в 8 байтов. Однако этот регистр имеет несколько полей, скажем, поле field1 находится в диапазоне от бита 0 до 4, field2 от бита 4 до 5, field3 от бита 5 до 8 и т. Д., Поэтому они различаются по количеству, длине и позиции в зависимости от регистра. Теперь я хочу прочитать информацию, применить маску к определенному полю, изменить это поле и записать информацию обратно на мое последовательное устройство. Я написал дополнительные функции для получения информации о количестве полей, смещений полей и ширины полей. То, чего я достиг на данный момент:

    read_value = read_register_byte(s, r, regName) #output: '00000000'
    #from hex to int
    read_value = int(read_value, 16)
    #from int to 32bit-bin without prefix
    read_value = format(read_value, '032b')

    #define mask range
    maskStart = len(read_value) - (offsets[fieldNo] + widths[fieldNo]) #for field0 this results in 28
    maskStop = len(read_value) - offsets[fieldNo] #this results in 32

    #create mask template (32bit)
    mask = [0]*32
    j = 0
    #insert F for mask range
    for i in read_value:
        mask[j] = read_value[j]
        if j >= maskStart and j < maskStop:
            mask[j]='F'
        j+=1
    #to string
    tempMask=""
    for i in mask:
        tempMask += i
    mask = tempMask
read_value
Out[96]: '00000000000000000000000000000000'

mask
Out[97]: '0000000000000000000000000000FFFF'

Что я пытаюсь сделать, это разрешить только модификацию тех битов, отмеченных F. Я уверен, что это очень плохая практика, однако это должно сработать, если я мог только выполнить следующие шаги: манипулировать read_value с моей маской, преобразовать мои данные обратно в этот 8-байтовый формат и записать на мое последовательное устройство.

Редактировать:

Field = namedtuple("Field", ["pos_lsb", "width"])
REG_WIDTH = 32 #r.width
REG_HEX_DIGITS = REG_WIDTH // 4

def create_mask(pos_lsb, width):
    mask = ((1 << width)-1) << pos_lsb
    return mask

def get_field(reg_value, field):
    mask = create_mask(*field)
    field_value = (reg_value & mask) >> field.pos_lsb
    return field_value

def set_field(reg_value, field, new_value):
    mask = create_mask(*field)
    reg_value = (reg_value & ~mask) | (new_value << field.pos_lsb)
    return reg_value

def value_from_string(reg_value_string):
    return int(reg_value_string, 16)

def value_to_string(reg_value):
    return f"{reg_value:0{REG_HEX_DIGITS}X}"

def write_field(s, r, regName, fieldNo, data):
    """ Writes to a single field of a Trixel register """
    """ debug block """
    # s = open_serial_port()
    # r = Registermap()
    # regName = 'tcm_control'
    # fieldNo = 0 #1st field
    # data = 5
    """ end of debug block """

    regAddress = r.get_register_address(regName)
    fields = r.get_register(regName, 'fields')
    offsets = r.get_register(regName, 'offsets')
    widths = r.get_register(regName, 'widths')

    if fieldNo+1 > fields:
        print('fieldNo out of range (max fields: ' + str(fields) + '). Aborting..')
        return 0

    fieldStart = r.baseAddress + regAddress + offsets[fieldNo]
    addr = r.baseAddress + regAddress
    register_value_string = read_register_byte(s, r, regName)
    field = Field(pos_lsb=offsets[fieldNo], width=widths[fieldNo])
    new_field_value = data

    # Update field
    print("Register: " + str(regName) + ", fieldNo: " + str(fieldNo+1) + "(" + str(fieldNo) + ")" + ", offset (hex): " + hex(fieldStart))
    print("Fieldname: " + str(r.get_register(regName,'descriptions')[fieldNo]))
    print(f"Original register value: {register_value_string}")
    reg_val = value_from_string(register_value_string)
    field_value = get_field(reg_val, field)
    print(f"Original field value: {field_value} (0x{field_value:x} in hex)")
    print(f"Setting field to {new_field_value} (0x{new_field_value:x} in hex)")
    reg_val = set_field(reg_val, field, new_field_value)
    field_value = get_field(reg_val, field)
    print(f"New field value: {field_value} (0x{field_value:x} in hex)")
    new_reg_val_string = value_to_string(reg_val)
    print(f"New register value to write to FPGA: {new_reg_val_string}")

    #write to FPGA
    cmd = ("mwr {:08X}".format(addr) + " " + new_reg_val_string + " \n").encode()
    message = s.write(cmd)

    if message != len(cmd):
        print('Error in Write! Bytes expected: ' + str(len(cmd)) + ', written: ' + str(message) + ', cmd: ' + str(cmd))
    elif message == len(cmd):
        print('Write to register ' + str(hex(addr)) + ' OK.')

Рабочий пример:

write_field(s, r, 'tcm_control', 3, 1)
Register: tcm_control, fieldNo: 4(3), offset (hex): 0x50000406
Fieldname: Should be released after configuring all TCM registers over AXI
Original register value: 00000071
Original field value: 1 (0x1 in hex)
Setting field to 1 (0x1 in hex)
New field value: 1 (0x1 in hex)
New register value to write to FPGA: 00000071
Write to register 0x50000400 OK.

Пример отказа:

write_field(s, r, 'tcm_control', 3, 2)
Register: tcm_control, fieldNo: 4(3), offset (hex): 0x50000406
Fieldname: Should be released after configuring all TCM registers over AXI
Original register value: 00000071
Original field value: 1 (0x1 in hex)
Setting field to 2 (0x2 in hex)
New field value: 0 (0x0 in hex)
New register value to write to FPGA: 000000B1
Write to register 0x50000400 OK.

read_register_byte(s, r, 'tcm_control')
Out[15]: '00000031'

1 Ответ

0 голосов
/ 14 апреля 2020

Я думаю, вы подходите к этому неправильно. Пожалуйста, посмотрите на этот (не очень прокомментированный) код и посмотрите, действительно ли это то, что вам нужно:

from collections import namedtuple

REG_WIDTH = 32
REG_HEX_DIGITS = REG_WIDTH // 4


Field = namedtuple("Field", ["pos_lsb", "width"])


def create_mask(pos_lsb, width):
    mask = ((1 << width)-1) << pos_lsb
    return mask


def get_field(reg_value, field):
    mask = create_mask(*field)
    field_value = (reg_value & mask) >> field.pos_lsb
    return field_value


def set_field(reg_value, field, new_value):
    mask = create_mask(*field)
    reg_value = (reg_value & ~mask) | (new_value << field.pos_lsb)
    return reg_value


def value_from_string(reg_value_string):
    return int(reg_value_string, 16)


def value_to_string(reg_value):
    return f"{reg_value:0{REG_HEX_DIGITS}X}"


register_value_string = "0F00F0FF"
field1 = Field(pos_lsb=3, width=5)
new_field_value = 0x12

# Update field1.
print(f"Original register value: {register_value_string}")
reg_val = value_from_string(register_value_string)
field_value = get_field(reg_val, field1)
print(f"Original field value: {field_value} (0x{field_value:x} in hex)")
print(f"Setting field to {new_field_value} (0x{new_field_value:x} in hex)")
reg_val = set_field(reg_val, field1, new_field_value)
field_value = get_field(reg_val, field1)
print(f"New field value: {field_value} (0x{field_value:x} in hex)")
new_reg_val_string = value_to_string(reg_val)
print(f"New register value to write to FPGA: {new_reg_val_string}")

Вывод:

Original register value: 0F00F0FF
Original field value: 31 (0x1f in hex)
Setting field to 18 (0x12 in hex)
New field value: 18 (0x12 in hex)
New register value to write to FPGA: 0F00F097

Я считаю, что это больше соответствует что бы вы хотели. Если вы хотите, чтобы я объяснил это подробнее, пожалуйста, дайте мне знать.

...