Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,31 @@

mbed-fastmodel-agent is a python module for Mbed OS GreenTea testing framework using FastModels FVP (Fixed Virtual Platforms).

This module only designed to work with [Greentea](https://github.com/ARMmbed/greentea) and [Htrun](https://github.com/ARMmbed/htrun),
This module only designed to work with [Greentea](https://github.com/ARMmbed/mbed-os-tools/tree/master/packages/mbed-greentea) and [Htrun](https://github.com/ARMmbed/mbed-os-tools/tree/master/packages/mbed-host-tests),
It enables enables Fast Models to run Mbed OS Greentea test suites.

If user only need to run mbed OS applications or examples rather than Greentea tests on Fast Models, please referencing [this mbed OS documents](https://os.mbed.com/docs/v5.10/tools/fast-models.html)


## Requirements
1. Make sure you have Arm Fast Models Libraries files installed to your host machines, as well as the Fast Models PyCADI.
2. A valid Fast Models license been set up correctly.
2. Install [Greentea](https://github.com/ARMmbed/greentea) latest master from GitHub (current 1.4.0 release do not contains the support for Fast Models)
3. Htrun Version 1.4.1 or later
1. Make sure you have Arm Fast Models Libraries files installed to your host machines, as well as the Fast Models PyCADI.

>please referencing [Fast Models User Guide](https://developer.arm.com/docs/100965/latest)

2. A valid Fast Models license been set up correctly.

>please referencing [Fast Models User Guide](https://developer.arm.com/docs/100965/latest)

3. Greentea version 1.5.0 or later
```
pip install mbed-greentea -U
mbedgt --version
```
4. Htrun version 1.4.1 or later
```
pip install mbed-host-tests -U
mbedhtrun --version
```

## Download
```
Expand Down Expand Up @@ -114,4 +128,5 @@ Then users need to edit `mbed-fastmodel-agent\fm_agent\settings.json` file eithe
Key `configs_add` can be added for additional config files for each model, Or Key `config` can be added to overwrite `GLOBAL` config files.

## Known limitations:
1. Fast Models normally have 3 or 4 serial terminal ports. But currently only one port is supported at moment.
1. Fast Models normally have 3 or 4 serial terminal ports. But currently only one port is used at moment.

21 changes: 21 additions & 0 deletions fm_agent/configs/COVERAGE.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
## Turn off terminal1 and terminal2, keep terminal0 open
fvp_mps2.telnetterminal1.quiet=1
fvp_mps2.telnetterminal2.quiet=1

## Control the output format of the telnet terminal
fvp_mps2.telnetterminal0.mode=raw


## Suppress the telnet/xterm to be launched, so that model agent can talk to the port
fvp_mps2.telnetterminal0.start_telnet=0


## logging the UART output to a file
# fvp_mps2.UART0.out_file=out_file.txt

## turn the rate limite off
fvp_mps2.mps2_visualisation.rate_limit-enable=0

## Enable Ethernet Port
fvp_mps2.hostbridge.userNetworking=1
fvp_mps2.smsc_91c111.enabled=1
4 changes: 2 additions & 2 deletions fm_agent/configs/DEFAULT.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,12 @@ fvp_mps2.telnetterminal2.quiet=1


## Control the output format of the telnet terminal
fvp_mps2.telnetterminal1.mode=raw
fvp_mps2.telnetterminal0.mode=raw


## Suppress the telnet/xterm to be launched, so that model agent can talk to the port
fvp_mps2.telnetterminal0.start_telnet=0


## logging the UART output to a file
# fvp_mps2.UART1.out_file=out_file.txt
# fvp_mps2.UART0.out_file=out_file.txt
6 changes: 3 additions & 3 deletions fm_agent/configs/FAST.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ fvp_mps2.telnetterminal2.quiet=1


## Control the output format of the telnet terminal
fvp_mps2.telnetterminal1.mode=raw
fvp_mps2.telnetterminal0.mode=raw


## Suppress the telnet/xterm to be launched, so that model agent can talk to the port
fvp_mps2.telnetterminal0.start_telnet=0


## logging the UART output to a file
# fvp_mps2.UART1.out_file=out_file.txt
# fvp_mps2.UART0.out_file=out_file.txt

## turn the rate limite off
fvp_mps2.mps2_visualisation.rate_limit-enable=0
fvp_mps2.mps2_visualisation.rate_limit-enable=0
6 changes: 3 additions & 3 deletions fm_agent/configs/NETWORK.conf
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,16 @@ fvp_mps2.telnetterminal2.quiet=1


## Control the output format of the telnet terminal
fvp_mps2.telnetterminal1.mode=raw
fvp_mps2.telnetterminal0.mode=raw


## Suppress the telnet/xterm to be launched, so that model agent can talk to the port
fvp_mps2.telnetterminal0.start_telnet=0


## Logging the UART output to a file
# fvp_mps2.UART1.out_file=out_file.txt
# fvp_mps2.UART0.out_file=out_file.txt

## Enable Ethernet Port
fvp_mps2.hostbridge.userNetworking=1
fvp_mps2.smsc_91c111.enabled=1
fvp_mps2.smsc_91c111.enabled=1
97 changes: 94 additions & 3 deletions fm_agent/fm_agent.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,8 @@ def setup_simulator(self, model_name, model_config):

def __connect_terminal(self):
""" connect socket terminal to a launched fastmodel"""

self.logger.prn_inf("Establishing socket connection to FastModel Terminal")
time.sleep(2)
try:
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.host, self.port))
Expand Down Expand Up @@ -146,13 +147,22 @@ def run_simulator(self):
def reset_simulator(self):
""" reset a launched fastmodel and connect terminal """
if self.is_simulator_alive():
self.model.stop()
self.logger.prn_wrn("STOP and RESTART FastModel")
self.__closeConnection()
self.model.release(shutdown=True)
time.sleep(1)
import fm.debug
self.model = fm.debug.LibraryModel(self.model_lib, self.model_params)
# check which host socket port is used for terminal0
terminal = self.model.get_target('fvp_mps2.telnetterminal0')
self.port = terminal.read_register('Port')
cpu = self.model.get_cpus()[0]
cpu.reset()
if self.image:
cpu.load_application(self.image)
self.logger.prn_wrn("RELOAD new image to FastModel")
self.model.run(blocking=False)
self.__connect_terminal()
self.logger.prn_wrn("Reconnect Terminal")
return True
else:
return False
Expand Down Expand Up @@ -219,9 +229,90 @@ def __closeConnection(self):
else:
self.logger.prn_inf("Terminal socket connection already closed")

def __run_to_breakpoint(self):
try:
self.model.run(timeout=15)
except:
# On timeout, model hangs
self.logger.prn_err("ERROR: Timeout reached without stop at breakpoint")
self.model.stop()
return False
else:
return True

def __CodeCoverage(self):
""" runs code coverage dump gcda file """

self.model.stop()
cpu = self.model.get_cpus()[0]

symbol_table = []
self.logger.prn_inf("Reading symbols from %s" % self.image)
if self.image:
symbol_table = read_symbol(self.image)

data_hex_addr = get_symbol_addr(symbol_table, "__gcov_var__ported")
data_int_addr = HexToInt(data_hex_addr)
self.logger.prn_inf("Address for [__gcov_var__ported] is %s" % data_hex_addr )

dump_hex_addr = get_symbol_addr(symbol_table, "__gcov_close__ported")
dump_int_addr = HexToInt(dump_hex_addr)
self.logger.prn_inf("Address for [__gcov_close__ported] is %s" % dump_hex_addr )

exit_hex_addr = get_symbol_addr(symbol_table, "collect_coverage")
exit_int_addr = HexToInt(exit_hex_addr)
self.logger.prn_inf("Address for [collect_coverage] is %s" % exit_hex_addr )



self.logger.prn_inf("Setting breakpoints...")
bkpt_dump = cpu.add_bpt_prog( dump_int_addr + 57 )
bkpt_exit = cpu.add_bpt_prog( exit_int_addr + 43 )

self.logger.prn_inf("Removing old gcda files...")
remove_gcda()

self.__run_to_breakpoint()
stopped_loc = cpu.read_register('Core.R15')

while stopped_loc == bkpt_dump.address :

start_addr = ByteToInt( cpu.read_memory( data_int_addr , size=4 ) )
end_addr = ByteToInt( cpu.read_memory( data_int_addr+4 , size=4 ) )
file_var_addr = ByteToInt( cpu.read_memory( data_int_addr+8 , size=4 ) )

file_var = r''
mem_char = " "

while ord(mem_char) != 0:
mem_char = cpu.read_memory(file_var_addr)
file_var += str(mem_char)
file_var_addr += 1

filename = file_var.rstrip(' \t\r\n\0')
self.logger.prn_inf("dumping to " + filename)
with open(filename, "wb") as f:
mem = cpu.read_memory(start_addr, count=(end_addr-start_addr))
f.write(mem)

if self.__run_to_breakpoint():
stopped_loc = cpu.read_register('Core.R15')
else:
stopped_loc = cpu.read_register('Core.R15')
break


if stopped_loc == bkpt_exit.address:
self.logger.prn_inf("Coverage dump program run to the end.")
else:
self.logger.prn_wrn("Coverage dump ended somewhere else!!")
lcov_collect(os.path.basename(self.image))

def shutdown_simulator(self):
""" shutdown fastmodel if any """
if self.is_simulator_alive():
if self.config_name == "COVERAGE":
self.__CodeCoverage()
self.logger.prn_inf("Fast-Model agent shutting down model")
self.__closeConnection()
self.model.release(shutdown=True)
Expand Down
10 changes: 5 additions & 5 deletions fm_agent/mbedfm.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,12 +34,12 @@ def print_version():
print(get_version())

def print_models():
print list_fastmodels()
print "Import PyCADI Test ... {}".format("PASSED" if check_import() else "FAILED")
print(list_fastmodels())
print("Import PyCADI Test ... {}".format("PASSED" if check_import() else "FAILED"))

def self_test():
print list_fastmodels(check_models=True)
print "Import PyCADI Test ... {}".format("PASSED" if check_import() else "FAILED")
print(list_fastmodels(check_models=True))
print("Import PyCADI Test ... {}".format("PASSED" if check_import() else "FAILED"))

def list_fastmodels(check_models=False):
"""! List all models and configs in fm_agent"""
Expand Down Expand Up @@ -84,7 +84,7 @@ def list_fastmodels(check_models=False):
c_test_cell.append("PASSED" if resource.is_simulator_alive() else "FAILED")
resource.shutdown_simulator()
except Exception as e:
print str(e)
print(str(e))
c_test_cell.append("FAILED")
else:
c_avail_cell.append("NO 'CONFIG FILE' NOT EXIST")
Expand Down
11 changes: 6 additions & 5 deletions fm_agent/settings.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,22 @@
{
"GLOBAL": {
"Windows":{
"PyCADI_path": "C:\\Program Files\\ARM\\FastModelsPortfolio_11.4\\lib\\python27",
"PyCADI_path": "C:\\work\\model_libs\\python27",
"model_lib_path": "C:\\work\\model_libs",
"configs": {
"DEFAULT": "DEFAULT.conf",
"NETWORK": "NETWORK.conf",
"FAST": "FAST.conf"
"COVERAGE":"COVERAGE.conf"
}
},
"Linux":{
"PyCADI_path": "/home/user/ARM/FastModelsPortfolio_11.4/lib/python2.7/",
"model_lib_path": "/home/user/model_libs",
"PyCADI_path": "/work/model_libs/python2.7/",
"model_lib_path": "/work/model_libs",
"configs": {
"DEFAULT": "DEFAULT.conf",
"FAST": "FAST.conf",
"NETWORK": "NETWORK.conf",
"FAST": "FAST.conf"
"COVERAGE":"COVERAGE.conf"
}
}
},
Expand Down
46 changes: 44 additions & 2 deletions fm_agent/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import time
import socket
import logging
import subprocess
from functools import partial

class SimulatorError(Exception):
Expand Down Expand Up @@ -94,8 +95,8 @@ def check_import():
import fm.debug
except ImportError as e:
for warning in warning_msgs:
print warning
print "Error: Failed to import fast models PyCADI!!!"
print(warning)
print("Error: Failed to import fast models PyCADI!!!")
return False
else:
return True
Expand Down Expand Up @@ -172,3 +173,44 @@ def find_free_port():
s.close()
return port

""" the following function mainly for coverage mode """

def read_symbol(image):
"""this function reads images symbol to a global variable"""
symbol_table = []
try:
symbol_table = subprocess.check_output('arm-none-eabi-readelf -sW "{}"'.format(image), shell=True).split("\n")
except Exception as e:
print("Make sure you have arm-none-eabi-readelf tool in PATH")
print("ERROR - {}.".format(str(e)))
sys.exit(1)
return symbol_table

def get_symbol_addr(symbol_table, symbol_name):
"""
Num: Value Size Type Bind Vis Ndx Name
24: 0002f45a 0 NOTYPE LOCAL DEFAULT 2 init_bss
25: 0002f470 0 NOTYPE LOCAL DEFAULT 2 system_startup
26: 0002f468 0 NOTYPE LOCAL DEFAULT 2 zero
"""
for line in symbol_table:
data = line.split()
if symbol_name in data:
return data[1]

def ByteToInt( byteList ):
return int(''.join( [ "{:02x}".format(x) for x in reversed(byteList) ] ),16)

def HexToInt( hex ):
return int(hex,16)

def lcov_collect(filename):
"""this function reads images symbol to a global variable"""
subprocess.call('lcov -c -d . --no-external -o BUILD/{}.info'.format(filename), shell=True)

def remove_gcda(rootdir="."):
"""this function removes gcda files"""
for root, dirs, files in os.walk(rootdir):
for file in files:
if file.endswith(".gcda"):
os.remove(os.path.join(root, file))
9 changes: 7 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

"""
mbed SDK
Copyright (c) 2011-2018 ARM Limited
Copyright (c) 2018-2019 ARM Limited

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -51,5 +51,10 @@ def read(fname):
license=LICENSE,
test_suite = 'test',
include_package_data=True,
install_requires=["PrettyTable>=0.7.2"])
install_requires=[
"PrettyTable>=0.7.2",
"mbed-host-tests>=1.4.1",
"mbed-greentea>=1.5.0"
]
)