import { Utility } from './utility' ; const MEM_DUMP_BOUNDARY = 16 ; export interface MemBlock { address : number ; size : number ; } export class MetaBlock { public address : number ; public size : number ; public memBlocks : Array < MemBlock > ; public data : Uint8Array | undefined ; public prevData : Uint8Array | undefined ; public title : string | undefined ; constructor ( address , size , memBlocks , title = undefined ) { this . address = address ; this . size = size ; this . memBlocks = memBlocks ; this . data = undefined ; this . prevData = undefined ; this . title = title ; } param address returns public isInRange ( address ) { for ( let memBlock of this . memBlocks ) { if ( address >= memBlock . address && address < memBlock . address + memBlock . size ) return true ; } return false ; } } /**
 * A memory dump object.
 * An array of meta blocks.
 */ export class MemoryDump { public metaBlocks = Array < MetaBlock > ( ) ; /**
     * Remove all memory blocks.
     */ public clearBlocks ( ) { this . metaBlocks . length = 0 ; } param startAddress param size param title public addBlock ( startAddress , size , title = undefined ) { const memBlock = { address : startAddress , size : size , data : [ ] } ; let bigBlock ; if ( size <= 0xFFFF - 2 * ( 2 * MEM_DUMP_BOUNDARY - 1 ) ) { const boundAddr = Utility . getBoundary ( memBlock . address - MEM_DUMP_BOUNDARY , MEM_DUMP_BOUNDARY ) ; const boundSize = Utility . getBoundary ( memBlock . address + memBlock . size - 1 , MEM_DUMP_BOUNDARY ) + 2 * MEM_DUMP_BOUNDARY - boundAddr ; bigBlock = new MetaBlock ( boundAddr , boundSize , [ memBlock ] , title ) ; } else { const boundAddr = Utility . getBoundary ( memBlock . address , MEM_DUMP_BOUNDARY ) ; const boundEnd = Utility . getBoundary ( memBlock . address + memBlock . size - 1 , MEM_DUMP_BOUNDARY ) + MEM_DUMP_BOUNDARY ; let boundSize = boundEnd - boundAddr + 1 ; if ( boundSize > 0xFFFF ) { boundSize = Math . trunc ( 0xFFFF / MEM_DUMP_BOUNDARY ) * MEM_DUMP_BOUNDARY ; memBlock . size = boundAddr + boundSize - startAddress ; } bigBlock = new MetaBlock ( boundAddr , boundSize , [ memBlock ] , title ) ; } this . metaBlocks . push ( bigBlock ) ; } param startAddress param size param title public addBlockWithoutBoundary ( startAddress , size , title = undefined ) { if ( size > 0x10000 ) size = 0x10000 ; const memBlock = { address : startAddress , size : size , data : [ ] } ; let bigBlock ; bigBlock = new MetaBlock ( startAddress , size , [ memBlock ] , title ) ; this . metaBlocks . push ( bigBlock ) ; } param blockIndex param startAddress param size public changeBlock ( blockIndex , startAddress , size , title = undefined ) { Utility . assert ( blockIndex < this . metaBlocks . length ) ; const memBlock = { address : startAddress , size : size , data : [ ] } ; let bigBlock ; let boundAddr ; let boundSize ; if ( size <= 0xFFFF - 2 * ( 2 * MEM_DUMP_BOUNDARY - 1 ) ) { boundAddr = Utility . getBoundary ( memBlock . address - MEM_DUMP_BOUNDARY , MEM_DUMP_BOUNDARY ) ; boundSize = Utility . getBoundary ( memBlock . address + memBlock . size - 1 , MEM_DUMP_BOUNDARY ) + 2 * MEM_DUMP_BOUNDARY - boundAddr ; } else { boundAddr = Utility . getBoundary ( memBlock . address , MEM_DUMP_BOUNDARY ) ; const boundEnd = Utility . getBoundary ( memBlock . address + memBlock . size - 1 , MEM_DUMP_BOUNDARY ) + MEM_DUMP_BOUNDARY ; let boundSize = boundEnd - boundAddr + 1 ; if ( boundSize > 0xFFFF ) { boundSize = Math . trunc ( 0xFFFF / MEM_DUMP_BOUNDARY ) * MEM_DUMP_BOUNDARY ; memBlock . size = boundAddr + boundSize - startAddress ; } } const metaBlock = this . metaBlocks [ blockIndex ] ; if ( metaBlock . address == boundAddr && metaBlock . size == boundSize ) { metaBlock . memBlocks = [ memBlock ] ; return ; } bigBlock = new MetaBlock ( boundAddr , boundSize , [ memBlock ] , title ) ; this . metaBlocks [ blockIndex ] = bigBlock ; } param address return public getValueFor ( address ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; const data = mb . data ; if ( data && index >= 0 && index < data . length ) { return data [ index ] ; } } return NaN ; } param address return public getPrevValueFor ( address ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; if ( mb . data && index >= 0 && index < mb . data . length ) { const data = mb . prevData ; if ( ! data ) return NaN ; return data [ index ] ; } } return NaN ; } param address param littleEndian return public getWordValueFor ( address , littleEndian ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; const data = mb . data ; if ( data && index >= 0 && index < data . length ) { if ( index + 1 >= data . length ) return NaN ; return Utility . getUintFromMemory ( data , index , 2 , littleEndian ) ; } } return NaN ; } param address param littleEndian return public getPrevWordValueFor ( address , littleEndian ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; if ( mb . data && index >= 0 && index < mb . data . length ) { const data = mb . prevData ; if ( ! data ) return NaN ; if ( index + 1 >= data . length ) return NaN ; return Utility . getUintFromMemory ( data , index , 2 , littleEndian ) ; } } return NaN ; } param address param value public setValueFor ( address , value ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; const data = mb . data ; if ( data && index >= 0 && index < data . length ) data [ index ] = value ; } } param address param value param littleEndian public setWordValueFor ( address , value , littleEndian ) { for ( let mb of this . metaBlocks ) { const index = address - mb . address ; const data = mb . data ; if ( data && index >= 0 && index + 1 < data . length ) { if ( littleEndian ) { data [ index ] = value & 0xFF ; data [ index + 1 ] = value >> 8 ; } else { data [ index + 1 ] = value & 0xFF ; data [ index ] = value >> 8 ; } } } } /**
     * Merges the address ranges if they are near to each other.
ranges.
     * Note: During merging the title of one of the blocks is lost. But they are anyway not used in this case.
     */ public mergeBlocks ( ) { this . metaBlocks . sort ( ( a , b ) => a . address - b . address ) ; const biggerBlocks = this . metaBlocks ; if ( biggerBlocks . length >= 2 ) { let prevBigBlock = biggerBlocks [ biggerBlocks . length - 1 ] ; for ( let i = biggerBlocks . length - 2 ; i >= 0 ; i -- ) { const curBigBlock = biggerBlocks [ i ] ; const prevAddr = prevBigBlock . address ; if ( prevAddr <= curBigBlock . address + curBigBlock . size + 1 + MEM_DUMP_BOUNDARY ) { const prevEndAddr = prevAddr + prevBigBlock . size ; if ( prevEndAddr > curBigBlock . address + curBigBlock . size ) { curBigBlock . size = prevEndAddr - curBigBlock . address ; } curBigBlock . memBlocks . push ( ... prevBigBlock . memBlocks ) ; biggerBlocks . splice ( i + 1 , 1 ) ; } prevBigBlock = curBigBlock ; } } this . metaBlocks = biggerBlocks ; } }