def cosimulate(self, sim_cycles, dut_factory, ref_factory, args, arg_types, **kwargs): return myhdl_cosimulation( sim_cycles, dut_factory, ref_factory, args, arg_types, **kwargs)
def cosimulate(self, sim_cycles, dut_factory, ref_factory, args, arg_types, **kwargs): return myhdl_cosimulation(sim_cycles, dut_factory, ref_factory, args, arg_types, **kwargs)
def test_data_read(self): ''' The master BFM should send the requested Address and Protections in the address transaction. The master BFM should correctly receive the Data and Response in the response transaction. ''' cycles = 4000 @block def testbench(clock): master_bfm = self.axi_lite.model( clock, self.nreset, self.axi_lite_interface) slave_write_bfm = self.SimpleAxiLiteWriteSlaveBFM( clock, self.nreset, self.axi_lite_interface) slave_read_bfm = self.SimpleAxiLiteReadSlaveBFM( clock, self.nreset, self.axi_lite_interface) add_read_transaction_prob = 0.05 t_check_state = enum( 'IDLE', 'TRANSACTIONS', 'CHECK_RESPONSE') check_state = Signal(t_check_state.IDLE) expected = {'addr': 0, 'prot': 0, 'data': 0, 'resp': 0,} control = {'addr_sent': False, 'data_sent': False, 'rd_data_transaction': None,} @always(clock.posedge) def check(): if check_state == t_check_state.IDLE: if random.random() < add_read_transaction_prob: # Create the random data that we will request from the # BFM. expected['addr'] = random.randint( 0, 2**self.addr_width-1) expected['prot'] = random.randint(0, 2**len( self.axi_lite_interface.ARPROT)-1) # At random times set up an axi lite read transaction self.axi_lite.add_read_transaction( read_address=expected['addr'], read_protection=expected['prot'], address_delay=random.randint(0, 15), data_delay=random.randint(0, 15)) control['addr_sent'] = False control['data_sent'] = False check_state.next = t_check_state.TRANSACTIONS elif check_state == t_check_state.TRANSACTIONS: if self.axi_lite_interface.ARVALID: # If valid is asserted, the requested address and # protection should be output. assert( self.axi_lite_interface.ARADDR== expected['addr']) assert( self.axi_lite_interface.ARPROT== expected['prot']) if self.axi_lite_interface.ARREADY: # Handshake has occurred. control['addr_sent'] = True if (self.axi_lite_interface.RVALID and self.axi_lite_interface.RREADY): # Record the response to check that the BFM receives # and reports it correctly expected['data'] = ( self.axi_lite_interface.RDATA) expected['resp'] = ( self.axi_lite_interface.RRESP) # Handshake has occurred. control['data_sent'] = True if (control['addr_sent'] and control['data_sent']): # All transactions have occured. check_state.next = t_check_state.CHECK_RESPONSE elif check_state == t_check_state.CHECK_RESPONSE: # Remove the response from the responses Queue and check # it is correct. try: control['rd_data_transaction'] = ( self.axi_lite.read_responses.get(True, timeout=1)) except queue.Empty: raise Exception("Timeout") assert(control['rd_data_transaction']['rd_data']==( expected['data'])) assert(control['rd_data_transaction']['rd_resp']==( expected['resp'])) check_state.next = t_check_state.IDLE return check, master_bfm, slave_write_bfm, slave_read_bfm myhdl_cosimulation( cycles, None, testbench, self.args, self.arg_types)
def test_write_signals_outside_of_transaction_values(self): ''' After a transaction has been added to a master BFM and before the transaction is complete, the following should be true: Whilst an address transaction has not happened and AWVALID has not been asserted, or after an address transaction has happened, the value on AWADDR and AWPROT should be different to that expected during the address transaction. Whilst a data transaction has not happened and WVALID has not been asserted, or after a data transaction has happened, the value on WDATA and WSTRB should be different to that expected during the data transaction. Note: These are not required by the AXI-Lite spec, but are to help prevent a class of bugs in which the data lines are read outside of their respective transactions. ''' cycles = 4000 @block def testbench(clock): master_bfm = self.axi_lite.model( clock, self.nreset, self.axi_lite_interface) slave_write_bfm = self.SimpleAxiLiteWriteSlaveBFM( clock, self.nreset, self.axi_lite_interface) slave_read_bfm = self.SimpleAxiLiteReadSlaveBFM( clock, self.nreset, self.axi_lite_interface) add_write_transaction_prob = 0.05 t_check_state = enum( 'IDLE', 'AWAITING_TRANSACTION_FIRST', 'AWAITING_TRANSACTION', 'ADDR_RECEIVED', 'DATA_RECEIVED', 'AWAITING_RESPONSE') check_state = Signal(t_check_state.IDLE) expected = {'addr': 0, 'data': 0, 'strbs': 0, 'prot': 0, 'resp': 0,} @always(clock.posedge) def check(): def check_address_sigs( awaiting_transaction=True, do_asserts=True): '''Check the signals are not what is expected unless the address transaction is happening. Return whether a transaction is happening. ''' if (awaiting_transaction and self.axi_lite_interface.AWVALID and self.axi_lite_interface.AWREADY): return True elif (awaiting_transaction and self.axi_lite_interface.AWVALID): # AWVALID has gone high so the addr should be correct return False else: if do_asserts: assert( self.axi_lite_interface.AWADDR != expected['addr']) assert( self.axi_lite_interface.AWPROT != expected['prot']) return False def check_data_sigs( awaiting_transaction=True, do_asserts=True): '''Check the signals are not what is expected unless the data transaction is happening. Return whether a transaction is happening. ''' if (awaiting_transaction and self.axi_lite_interface.WVALID and self.axi_lite_interface.WREADY): return True elif (awaiting_transaction and self.axi_lite_interface.WVALID): # WVALID has gone high so the data should be correct return False else: if do_asserts: assert( self.axi_lite_interface.WDATA != expected['data']) assert( self.axi_lite_interface.WSTRB != expected['strbs']) return False if check_state == t_check_state.IDLE: if random.random() < add_write_transaction_prob: # Create the random data that we will request from the # BFM. expected['addr'] = random.randint( 0, 2**self.addr_width-1) expected['data'] = random.randint( 0, 2**self.data_width-1) expected['strbs'] = random.randint( 0, 2**self.wstrb_width-1) expected['prot'] = random.randint(0, 2**len( self.axi_lite_interface.AWPROT)-1) # Set up an axi lite write transaction self.axi_lite.add_write_transaction( write_address=expected['addr'], write_data=expected['data'], write_strobes=expected['strbs'], write_protection=expected['prot'], address_delay=random.randint(0, 15), data_delay=random.randint(0, 15), response_ready_delay=random.randint(10, 25)) check_state.next = ( t_check_state.AWAITING_TRANSACTION_FIRST) elif check_state == t_check_state.AWAITING_TRANSACTION_FIRST: # In the first cycle, the set up hasn't happened yet so # we shouldn't check the value. addr_transaction_happened = ( check_address_sigs(do_asserts=False)) data_transaction_happened = ( check_data_sigs(do_asserts=False)) if (addr_transaction_happened and data_transaction_happened): check_state.next = t_check_state.AWAITING_RESPONSE elif addr_transaction_happened: check_state.next = t_check_state.ADDR_RECEIVED elif data_transaction_happened: check_state.next = t_check_state.DATA_RECEIVED else: check_state.next = t_check_state.AWAITING_TRANSACTION elif check_state == t_check_state.AWAITING_TRANSACTION: addr_transaction_happened = check_address_sigs() data_transaction_happened = check_data_sigs() if (addr_transaction_happened and data_transaction_happened): check_state.next = t_check_state.AWAITING_RESPONSE elif addr_transaction_happened: check_state.next = t_check_state.ADDR_RECEIVED elif data_transaction_happened: check_state.next = t_check_state.DATA_RECEIVED elif check_state == t_check_state.ADDR_RECEIVED: addr_transaction_happened = check_address_sigs(False) data_transaction_happened = check_data_sigs() if data_transaction_happened: check_state.next = t_check_state.AWAITING_RESPONSE elif check_state == t_check_state.DATA_RECEIVED: addr_transaction_happened = check_address_sigs() data_transaction_happened = check_data_sigs(False) if addr_transaction_happened: check_state.next = t_check_state.AWAITING_RESPONSE elif check_state == t_check_state.AWAITING_RESPONSE: check_address_sigs(False) check_data_sigs(False) if (self.axi_lite_interface.BVALID and self.axi_lite_interface.BREADY): check_state.next = t_check_state.IDLE else: pass return check, master_bfm, slave_write_bfm, slave_read_bfm myhdl_cosimulation( cycles, None, testbench, self.args, self.arg_types)
def test_valid(self): ''' Once VALID is asserted it must remain asserted until the handshake occurs, a rising clock edge at which VALID and READY are both asserted. ''' cycles = 4000 @block def testbench(clock): master_bfm = self.axi_lite.model( clock, self.nreset, self.axi_lite_interface) slave_write_bfm = self.SimpleAxiLiteWriteSlaveBFM( clock, self.nreset, self.axi_lite_interface) slave_read_bfm = self.SimpleAxiLiteReadSlaveBFM( clock, self.nreset, self.axi_lite_interface) add_write_transaction_prob = 0.05 add_read_transaction_prob = 0.05 check_enable = {'awvalid': False, 'wvalid': False, 'arvalid': False} @always(clock.posedge) def check(): if random.random() < add_write_transaction_prob: # At random times set up an axi lite write transaction self.axi_lite.add_write_transaction( write_address=random.randint( 0, 2**self.addr_width-1), write_data=random.randint(0, 2**self.data_width-1), write_strobes=random.randint( 0, 2**self.wstrb_width-1), write_protection=random.randint(0, 2**len( self.axi_lite_interface.AWPROT)-1), address_delay=random.randint(0, 15), data_delay=random.randint(0, 15), response_ready_delay=random.randint(10, 25)) if random.random() < add_read_transaction_prob: # At random times set up an axi lite read transaction self.axi_lite.add_read_transaction( read_address=random.randint(0, 2**self.addr_width-1), read_protection=random.randint(0, 2**len( self.axi_lite_interface.ARPROT)-1), address_delay=random.randint(0, 15), data_delay=random.randint(0, 15)) try: # Try to remove any responses from the responses Queue. # In this test we are not actually interested in the # response but we want to prevent the queue from filling # up self.axi_lite.write_responses.get(False) except queue.Empty: pass if (self.axi_lite_interface.AWVALID and self.axi_lite_interface.AWREADY): # Handshake has occured do not need to check that AWVALID # stays high. check_enable['awvalid'] = False elif self.axi_lite_interface.AWVALID: # Once AWVALID is set it should remain high until the # handshake occurs check_enable['awvalid'] = True if (self.axi_lite_interface.WVALID and self.axi_lite_interface.WREADY): # Handshake has occured do not need to check that WVALID # stays high. check_enable['wvalid'] = False elif self.axi_lite_interface.WVALID: # Once WVALID is set it should remain high until the # handshake occurs check_enable['wvalid'] = True if (self.axi_lite_interface.ARVALID and self.axi_lite_interface.ARREADY): # Handshake has occured do not need to check that ARVALID # stays high. check_enable['arvalid'] = False elif self.axi_lite_interface.ARVALID: # Once ARVALID is set it should remain high until the # handshake occurs check_enable['arvalid'] = True if check_enable['awvalid']: assert( self.axi_lite_interface.AWVALID == True) if check_enable['wvalid']: assert( self.axi_lite_interface.WVALID == True) if check_enable['arvalid']: assert( self.axi_lite_interface.ARVALID == True) return check, master_bfm, slave_write_bfm, slave_read_bfm myhdl_cosimulation( cycles, None, testbench, self.args, self.arg_types)
def test_nreset(self): ''' On nreset the Master should drive ARVALID, AWVALID and WVALID low. It may only next drive the valid signals one rising edge after the nreset signal goes high. We do not care about the other signals. ''' cycles = 4000 @block def testbench(clock): master_bfm = self.axi_lite.model( clock, self.nreset, self.axi_lite_interface) slave_write_bfm = self.SimpleAxiLiteWriteSlaveBFM( clock, self.nreset, self.axi_lite_interface) slave_read_bfm = self.SimpleAxiLiteReadSlaveBFM( clock, self.nreset, self.axi_lite_interface) nreset_high_prob = 0.1 nreset_low_prob = 0.05 add_write_transaction_prob = 0.05 add_read_transaction_prob = 0.05 t_check_state = enum('IDLE', 'CHECK_RESET') check_state = Signal(t_check_state.IDLE) @always(clock.posedge) def check(): if not self.nreset and (random.random() < nreset_high_prob): self.nreset.next = True elif self.nreset and (random.random() < nreset_low_prob): self.nreset.next = False if random.random() < add_write_transaction_prob: # At random times set up an axi lite write transaction self.axi_lite.add_write_transaction( write_address=random.randint( 0, 2**self.addr_width-1), write_data=random.randint(0, 2**self.data_width-1), write_strobes=random.randint( 0, 2**self.wstrb_width-1), write_protection=random.randint(0, 2**len( self.axi_lite_interface.AWPROT)-1), address_delay=random.randint(0, 15), data_delay=random.randint(0, 15), response_ready_delay=random.randint(10, 25)) if random.random() < add_read_transaction_prob: # At random times set up an axi lite read transaction self.axi_lite.add_read_transaction( read_address=random.randint(0, 2**self.addr_width-1), read_protection=random.randint(0, 2**len( self.axi_lite_interface.ARPROT)-1), address_delay=random.randint(0, 15), data_delay=random.randint(0, 15)) try: # Try to remove any responses from the responses Queue. # In this test we are not actually interested in the # response but we want to prevent the queue from filling # up self.axi_lite.write_responses.get(False) except queue.Empty: pass try: # Try to remove any responses from the responses Queue. # In this test we are not actually interested in the # response but we want to prevent the queue from filling # up self.axi_lite.read_responses.get(False) except queue.Empty: pass if check_state == t_check_state.IDLE: if not self.nreset: # Reset has been received so move onto the check_nreset # state. check_state.next = t_check_state.CHECK_RESET if check_state == t_check_state.CHECK_RESET: assert( self.axi_lite_interface.ARVALID==False) assert( self.axi_lite_interface.AWVALID==False) assert( self.axi_lite_interface.WVALID==False) if self.nreset: # No longer being nreset so return to IDLE check_state.next = t_check_state.IDLE return check, master_bfm, slave_write_bfm, slave_read_bfm myhdl_cosimulation( cycles, None, testbench, self.args, self.arg_types)