Python Coroutines in Simics Snoop module reference
Python Coroutines in Simics  / 

1 Introduction

Coroutines are a language mechanism that allows suspension and resumption of a subroutine. Coroutines are a useful tool when writing tests for target software, since it allows test logic to be expressed in a linear manner, typically by waiting for the system to enter a particular state, inject a stimuli, awaiting a reaction and validate that reaction.

The recommended way to implement coroutines in the Python language is through the async/await syntax, and the asyncio library.

This document presents two libraries that together leverage asyncio-style Python coroutines in Simics: The snoop library, which provides a unified representation of simulation events, and the sloop library which allows snoopers to be used within asyncio.

1.1 Snoopers

A snooper is a Python object responsible for monitoring a particular kind of simulation event. Snoopers offer a unified API for registering callbacks.

The primary operation of a snooper is its add_callback method, which registers a callback on the snooped event. The callback will then be called repeatedly until it is canceled, which is done by calling the cancel method on the Handle object returned by add_callback. The add_callback method is typically not called directly; for most use cases there are utilities that manage things like cancellations automatically in a safe manner.

1.2 Sloop

The sloop library is an integration of Python's asyncio library with the Simics scheduler. The library provides means to create and run tasks based on coroutine functions (declared in Python using the async def syntax), but where the progression of an asyncio coroutine typically depends on asynchronous operating system events on the host machine, the progression of a sloop coroutine instead depends on simulation events. The API of the sloop library generally imitates asyncio, but only supports a subset of all functions available in asyncio. Most notably, sloop.create_task spawns a task which can await simulation events, and sloop.run_until_complete runs simulation until a sloop-based awaitable yields, similar to the run-until commands in Simics CLI.

The sloop library also contains some primitives specific to Simics, in particular:

1.3 Integration with script-branches

Script branches serve a similar purpose as sloop coroutines; just like coroutines, script branches are Python subroutines that run piecewise in Global Context to provide an asynchronous behaviour. Thanks to this similarity, the script_branch module provides a two-way integration between script-branches and sloop coroutines; this permits gradual migration of script-branches to sloop coroutines:

1.4 Integration with the Breakpoint Manager

The breakpoint manager, represented by the bp configuration object, provides a number of breakpoint types, which are similar in spirit to snoopers: Like a snooper, a breakpoint type represents an observable simulation event, and provides various options for awaiting or tracing this event. The bp-manager module provides a generic wrapper that turns a breakpoint type into a snooper: The Python class simmod.bp_manager.snooper.BP(obj, *args, **kwargs) is a snooper based on the breakpoint type represented by the configuration object obj, where args and kwargs are interpreted as CLI arguments to the breakpoint type. For instance, the command bp.log.run-until substr = "a.*b" -regexp, which has a direct Python wrapping conf.bp.log.cli_cmds.run_until(substr='a.*b', regexp=True), can be wrapped in a snooper as simmod.bp_manager.snooper.BP(conf.bp.log, substr='a.*b', regexp=True).

Python Coroutines in Simics Snoop module reference