Skip to content

Commit

Permalink
Properly handle read bursts in AXI model
Browse files Browse the repository at this point in the history
  • Loading branch information
alexforencich committed Aug 13, 2018
1 parent 7e18825 commit a962dfc
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 41 deletions.
65 changes: 44 additions & 21 deletions tb/axi.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ def __init__(self):
self.int_read_addr_sync = Signal(False)
self.int_read_resp_command_queue = []
self.int_read_resp_command_sync = Signal(False)
self.int_read_resp_queue = []
self.int_read_resp_queue_list = {}
self.int_read_resp_sync = Signal(False)

self.in_flight_operations = 0
Expand Down Expand Up @@ -189,7 +189,7 @@ def create_logic(self,
rpause=False,
name=None
):

if self.has_logic:
raise Exception("Logic already instantiated!")

Expand Down Expand Up @@ -438,7 +438,9 @@ def read_logic():

cycles = int((length + num_bytes-1 + (addr % num_bytes)) / num_bytes)

self.int_read_resp_command_queue.append((addr, length, size, cycles, prot))
burst_list = []

self.int_read_resp_command_queue.append((addr, length, size, cycles, prot, burst_list))
self.int_read_resp_command_sync.next = not self.int_read_resp_command_sync

cur_addr = aligned_addr
Expand All @@ -455,20 +457,23 @@ def read_logic():
burst_length = int((min(burst_length*num_bytes, 0x1000-(cur_addr&0xfff))+num_bytes-1)/num_bytes) # 4k align
arid = self.cur_read_id
self.cur_read_id = (self.cur_read_id + 1) % 2**len(m_axi_arid)
burst_list.append((arid, burst_length))
self.int_read_addr_queue.append((cur_addr, arid, burst_length-1, size, burst, lock, cache, prot, qos, region, user))
self.int_read_addr_sync.next = not self.int_read_addr_sync
if name is not None:
print("[%s] Read burst arid: 0x%x araddr: 0x%08x arlen: %d arsize: %d" % (name, arid, cur_addr, burst_length-1, size))

cur_addr += num_bytes

burst_list.append(None)

@instance
def read_resp_logic():
while True:
if not self.int_read_resp_command_queue:
yield self.int_read_resp_command_sync

addr, length, size, cycles, prot = self.int_read_resp_command_queue.pop(0)
addr, length, size, cycles, prot, burst_list = self.int_read_resp_command_queue.pop(0)

num_bytes = 2**size
assert 0 <= size <= int(math.log(bw, 2))
Expand All @@ -484,29 +489,46 @@ def read_resp_logic():

resp = 0

for k in range(cycles):
if not self.int_read_resp_queue:
yield self.int_read_resp_sync
first = True

cycle_id, cycle_data, cycle_resp, cycle_last, cycle_user = self.int_read_resp_queue.pop(0)
while True:
while not burst_list:
yield clk.posedge

if cycle_resp != 0:
resp = cycle_resp
cur_burst = burst_list.pop(0)

start = cycle_offset
stop = cycle_offset+num_bytes
if cur_burst is None:
break

if k == 0:
start = start_offset
if k == cycles-1:
stop = end_offset
rid = cur_burst[0]
burst_length = cur_burst[1]

assert cycle_last == (k == cycles - 1)
for k in range(burst_length):
self.int_read_resp_queue_list.setdefault(rid, [])
while not self.int_read_resp_queue_list[rid]:
yield self.int_read_resp_sync

for j in range(start, stop):
data += bytearray([(cycle_data >> j*8) & 0xff])
cycle_id, cycle_data, cycle_resp, cycle_last, cycle_user = self.int_read_resp_queue_list[rid].pop(0)

cycle_offset = (cycle_offset + num_bytes) % bw
if cycle_resp != 0:
resp = cycle_resp

start = cycle_offset
stop = cycle_offset+num_bytes

if first:
start = start_offset

assert cycle_last == (k == burst_length - 1)

for j in range(start, stop):
data += bytearray([(cycle_data >> j*8) & 0xff])

cycle_offset = (cycle_offset + num_bytes) % bw

first = False

data = data[:length]

if name is not None:
print("[%s] Read data addr: 0x%08x prot: 0x%x data: %s" % (name, addr, prot, " ".join(("{:02x}".format(c) for c in bytearray(data)))))
Expand Down Expand Up @@ -563,7 +585,8 @@ def read_resp_interface_logic():
ruser = int(m_axi_ruser)
else:
ruser = 0
self.int_read_resp_queue.append((rid, rdata, rresp, rlast, ruser))
self.int_read_resp_queue_list.setdefault(rid, [])
self.int_read_resp_queue_list[rid].append((rid, rdata, rresp, rlast, ruser))
self.int_read_resp_sync.next = not self.int_read_resp_sync

return instances()
Expand Down
60 changes: 40 additions & 20 deletions tb/test_axi.py
Original file line number Diff line number Diff line change
Expand Up @@ -229,80 +229,100 @@ def check():
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))

assert axi_ram_inst.read_mem(0,4) == b'test'
assert axi_ram_inst.read_mem(0, 4) == b'test'

yield delay(100)

yield clk.posedge
print("test 3: write via port0")
current_test.next = 3

axi_master_inst.init_write(4, b'\x11\x22\x33\x44')
addr = 4
test_data = b'\x11\x22\x33\x44'

axi_master_inst.init_write(addr, test_data)

yield axi_master_inst.wait()
yield clk.posedge

data = axi_ram_inst.read_mem(0, 32)
data = axi_ram_inst.read_mem(addr&0xffffff80, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))

assert axi_ram_inst.read_mem(4,4) == b'\x11\x22\x33\x44'
assert axi_ram_inst.read_mem(addr, len(test_data)) == test_data

yield delay(100)

yield clk.posedge
print("test 4: read via port0")
current_test.next = 4

axi_master_inst.init_read(4, 4)
addr = 4
test_data = b'\x11\x22\x33\x44'

axi_ram_inst.write_mem(addr, test_data)

axi_master_inst.init_read(addr, len(test_data))

yield axi_master_inst.wait()
yield clk.posedge

data = axi_master_inst.get_read_data()
assert data[0] == 4
assert data[1] == b'\x11\x22\x33\x44'
assert data[0] == addr
assert data[1] == test_data

yield delay(100)

yield clk.posedge
print("test 5: various writes")
current_test.next = 5

for length in range(1,8):
for offset in range(4,8):
for length in list(range(1,8))+[1024]:
for offset in list(range(4,8))+[4096-4]:
for size in (2, 1, 0):
for wait in wait_normal, wait_pause_master, wait_pause_slave:
axi_ram_inst.write_mem(256*(16*offset+length), b'\xAA'*32)
axi_master_inst.init_write(256*(16*offset+length)+offset, b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length], size=size)
print("length %d, offset %d, size %d"% (length, offset, size))
addr = 256*(16*offset+length)+offset
test_data = bytearray([x%256 for x in range(length)])

axi_ram_inst.write_mem(addr&0xffffff80, b'\xAA'*(length+256))
axi_master_inst.init_write(addr, test_data, size=size)

yield wait()
yield clk.posedge

data = axi_ram_inst.read_mem(256*(16*offset+length), 32)
data = axi_ram_inst.read_mem(addr&0xffffff80, 32)
for i in range(0, len(data), 16):
print(" ".join(("{:02x}".format(c) for c in bytearray(data[i:i+16]))))

assert axi_ram_inst.read_mem(256*(16*offset+length)+offset, length) == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
assert axi_ram_inst.read_mem(256*(16*offset+length)+offset-1, 1) == b'\xAA'
assert axi_ram_inst.read_mem(256*(16*offset+length)+offset+length, 1) == b'\xAA'
assert axi_ram_inst.read_mem(addr, length) == test_data
assert axi_ram_inst.read_mem(addr-1, 1) == b'\xAA'
assert axi_ram_inst.read_mem(addr+length, 1) == b'\xAA'

yield delay(100)

yield clk.posedge
print("test 6: various reads")
current_test.next = 6

for length in range(1,8):
for offset in range(4,8):
for length in list(range(1,8))+[1024]:
for offset in list(range(4,8))+[4096-4]:
for size in (2, 1, 0):
for wait in wait_normal, wait_pause_master, wait_pause_slave:
axi_master_inst.init_read(256*(16*offset+length)+offset, length, size=size)
print("length %d, offset %d, size %d"% (length, offset, size))
addr = 256*(16*offset+length)+offset
test_data = bytearray([x%256 for x in range(length)])

axi_ram_inst.write_mem(addr, test_data)

axi_master_inst.init_read(addr, length, size=size)

yield wait()
yield clk.posedge

data = axi_master_inst.get_read_data()
assert data[0] == 256*(16*offset+length)+offset
assert data[1] == b'\x11\x22\x33\x44\x55\x66\x77\x88'[0:length]
assert data[0] == addr
assert data[1] == test_data

yield delay(100)

Expand Down

0 comments on commit a962dfc

Please sign in to comment.