<s> from collections import defaultdict <EOL> class ObservableMemory : <EOL> def __init__ ( self , subject = None , addrWidth = <NUM_LIT:16> ) : <EOL> self . physMask = <NUM_LIT> <EOL> if addrWidth > <NUM_LIT:16> : <EOL> self . physMask = <NUM_LIT> <EOL> if subject is None : <EOL> subject = ( self . physMask + <NUM_LIT:1> ) * [ <NUM_LIT> ] <EOL> self . _subject = subject <EOL> self . _read_subscribers = defaultdict ( list ) <EOL> self . _write_subscribers = defaultdict ( list ) <EOL> def __setitem__ ( self , address , value ) : <EOL> if isinstance ( address , slice ) : <EOL> r = range ( * address . indices ( self . physMask + <NUM_LIT:1> ) ) <EOL> for n , v in zip ( r , value ) : <EOL> self [ n ] = v <EOL> return <EOL> address &= self . physMask <EOL> callbacks = self . _write_subscribers [ address ] <EOL> for callback in callbacks : <EOL> result = callback ( address , value ) <EOL> if result is not None : <EOL> value = result <EOL> self . _subject [ address ] = value <EOL> def __getitem__ ( self , address ) : <EOL> if isinstance ( address , slice ) : <EOL> r = range ( * address . indices ( self . physMask + <NUM_LIT:1> ) ) <EOL> return [ self [ n ] for n in r ] <EOL> address &= self . physMask <EOL> callbacks = self . _read_subscribers [ address ] <EOL> final_result = None <EOL> for callback in callbacks : <EOL> result = callback ( address ) <EOL> if result is not None : <EOL> final_result = result <EOL> if final_result is None : <EOL> return self . _subject [ address ] <EOL> else : <EOL> return final_result <EOL> def __getattr__ ( self , attribute ) : <EOL> return getattr ( self . _subject , attribute ) <EOL> def subscribe_to_write ( self , address_range , callback ) : <EOL> for address in address_range : <EOL> address &= self . physMask <EOL> callbacks = self . _write_subscribers . setdefault ( address , [ ] ) <EOL> if callback not in callbacks : <EOL> callbacks . append ( callback ) <EOL> def subscribe_to_read ( self , address_range , callback ) : <EOL> for address in address_range : <EOL> address &= self . physMask <EOL> callbacks = self . _read_subscribers . setdefault ( address , [ ] ) <EOL> if callback not in callbacks : <EOL> callbacks . append ( callback ) <EOL> def write ( self , start_address , bytes ) : <EOL> start_address &= self . physMask <EOL> self . _subject [ start_address : start_address + len ( bytes ) ] = bytes </s>
