import { Labels } from '../labels/labels' ; import { DebugProtocol } from 'vscode-debugprotocol/lib/debugProtocol' ; import { Settings } from '../settings' ; import { Utility } from '../misc/utility' ; import { RefList } from '../misc/reflist' ; import { Remote } from '../remotes/remotebase' ; import { Format } from '../disassembler/format' ; import { DisassemblyClass } from '../misc/disassembly' ; import { StepHistory } from '../remotes/cpuhistory' ; /**
 * Represents a variable.
 * Variables know how to retrieve the data from the remote.
 */ export class ShallowVar { public static pcChanged = false ; public static spChanged = false ; public static otherRegisterChanged = false ; public static memoryChanged = false ; public static clearChanged ( ) { this . pcChanged = false ; this . spChanged = false ; this . otherRegisterChanged = false ; this . memoryChanged = false ; } param start param count public async getContent ( start , count ) { return [ ] ; } param name param value returns public async setValue ( name , value ) { return undefined as any ; } param name returns public changeable ( name ) { if ( StepHistory . isInStepBackMode ( ) ) return 'Altering values not allowed in time-travel mode.' ; return undefined ; } } /**
 * Represents a ShallowVar that is const, i.e. not changeable by the user.
 */ export class ShallowVarConst extends ShallowVar { param name returns public changeable ( name ) { return 'You cannot alter this value.' ; } } /**
 * The DisassemblyVar class knows how to retrieve the disassembly from the remote.
 */ export class DisassemblyVar extends ShallowVarConst { public address : number ; public count : number ; protected disassemblyHistory : Array < { address : number ; text : string ; } > ; returns public async getContent ( start , count ) { start = start || 0 ; count = count || ( this . count - start ) ; const end = start + count ; const size = 4 * this . count ; const data = await Remote . readMemoryDump ( this . address , size ) ; const dasmArray = DisassemblyClass . getLines ( this . address , data , this . count ) ; const list = new Array < DebugProtocol . Variable > ( ) ; const dasmFiltered = dasmArray . filter ( ( value , index ) => ( index >= start && index < end ) ) ; for ( const entry of dasmFiltered ) { const address = entry . address ; const addrString = Format . getHexString ( address ) . toUpperCase ( ) ; const labels = Labels . getLabelsForNumber64k ( address ) ; let addrLabel = addrString ; if ( labels ) addrLabel = labels . join ( ',\n' ) ; list . push ( { name : addrString , type : addrLabel , value : entry . instruction , variablesReference : 0 } ) ; } return list ; } } /**
 * The MemorySlotsVar class knows how to retrieve the mapping of
 * memory slots and banks from Remote.
 */ export class MemorySlotsVar extends ShallowVarConst { /**
     * Constructor.
     */ public constructor ( ) { super ( ) ; } returns public async getContent ( start , count ) { start = start || 0 ; const memoryBanks = await Remote . getMemoryBanks ( ) ; count = count || ( memoryBanks . length - start ) ; let slot = - 1 ; const segments = new Array < DebugProtocol . Variable > ( count ) ; for ( let i = 0 ; i < count ; i ++ ) { const bank = memoryBanks [ i + start ] ; const name = Utility . getHexString ( bank . start , 4 ) + '-' + Utility . getHexString ( bank . end , 4 ) ; slot ++ ; const slotString = slot . toString ( ) ; segments [ i ] = { name : slotString + ": " + name , type : "Slot " + slotString , value : bank . name , variablesReference : 0 } ; } return segments ; } } /**
 * The RegistersMainVar class knows how to retrieve the register values from Remote.
 */ export class RegistersMainVar extends ShallowVar { returns public async getContent ( start , count ) { start = start || 0 ; const regNames = this . registerNames ( ) ; count = count || ( regNames . length - start ) ; const registers = new Array < DebugProtocol . Variable > ( count ) ; for ( let i = 0 ; i < count ; i ++ ) { const regName = regNames [ i + start ] ; const formattedValue = Remote . getVarFormattedReg ( regName ) ; registers [ i ] = { name : regName , type : formattedValue , value : formattedValue , variablesReference : 0 } ; } return registers ; } param name param value returns public async setValue ( name , value ) { if ( ! isNaN ( value ) ) { await Remote . setRegisterValue ( name , value ) ; await Remote . getRegistersFromEmulator ( ) ; if ( name == "PC" ) { StepHistory . clear ( ) ; ShallowVar . pcChanged = true ; } if ( name == "SP" ) { StepHistory . clear ( ) ; ShallowVar . spChanged = true ; } else { ShallowVar . otherRegisterChanged = true ; } } const formatted = Remote . getVarFormattedReg ( name ) ; return formatted ; } param name returns /**
     * Returns the register names to show. The 1rst half of the registers.
     */ protected registerNames ( ) { return [ "PC" , "SP" , "A" , "F" , "HL" , "DE" , "BC" , "IX" , "IY" , "B" , "C" , "D" , "E" , "H" , "L" ] ; } } /**
 * The RegistersMainVar class knows how to retrieve the register values from zeasrux.
 */ export class RegistersSecondaryVar extends RegistersMainVar { /**
     * Returns the register names to show. The 2nd half of the registers.
     */ protected registerNames ( ) { return [ "A'" , "F'" , "HL'" , "DE'" , "BC'" , "IXH" , "IXL" , "IYH" , "IYL" , "I" , "R" , "IM" ] ; } } /**
 * The StackVar represents the stack variables. I.e. the pushed
 * registers that are on the stack. This stack contains only the pushed registers
 * until the next CALL return address.
 */ export class StackVar extends ShallowVar { private stack : Array < number > ; private stackAddress : number ; param stack param stackAddress public setFrameAddress ( stack , stackAddress ) { this . stack = stack ; this . stackAddress = stackAddress ; } returns public async getContent ( start , count ) { start = start || 0 ; count = count || ( this . stack . length - start ) ; const format = Settings . launch . formatting . stackVar ; const tabSizes = Utility . calculateTabSizes ( format , 2 ) ; const stackList = new Array < DebugProtocol . Variable > ( count ) ; let undefText = "unknown" ; for ( let i = 0 ; i < count ; i ++ ) { const index = i + start ; const value = this . stack [ index ] ; const formatted = await Utility . numberFormatted ( '' , value , 2 , format , tabSizes , undefText ) ; stackList [ i ] = { name : Utility . getHexString ( this . stackAddress - 2 * index , 4 ) , type : formatted , value : formatted , variablesReference : 0 } ; undefText = undefined as any ; } return stackList ; } param name param value returns public async setValue ( name , value ) { const address = Utility . parseValue ( name + 'h' ) ; if ( ! isNaN ( address ) && ! isNaN ( value ) ) { if ( value < 0 ) value += 0x10000 ; const data = new Uint8Array ( 2 ) ; data [ 0 ] = value & 0xFF ; data [ 1 ] = value >>> 8 ; await Remote . writeMemoryDump ( address , data ) ; ShallowVar . memoryChanged = true ; } const data = await Remote . readMemoryDump ( address , 2 ) ; const memWord = data [ 0 ] + ( data [ 1 ] << 8 ) ; const formattedString = Utility . numberFormatted ( name , memWord , 2 , Settings . launch . formatting . stackVar , undefined ) ; return formattedString ; } } /**
 * Object used for the SubStructVar to store elements in the array.
 */ interface SubStructItems { address : number ; elemSize : number ; itemRef : number | ( ( ) => string ) ; indexedVariables : number ; } /**
 * The StructVar class is a container class which holds other properties (the elements of the
 * struct). I.e. SubStructVars.
 * The StructVar is the parent object which also holds the memory contents.
 * The SubStructVars refer to it.
 */ export class SubStructVar extends ShallowVar { protected propMap = new Map < string , SubStructItems > ( ) ; protected littleEndian : boolean ; param relIndex param count param elemSize param struct param props param list param parentStruct public constructor ( relIndex , count , elemSize , struct , props , list , parentStruct ? ) { super ( ) ; if ( parentStruct ) { this . littleEndian = parentStruct . littleEndian ; this . createPropArray ( relIndex , count , elemSize , struct , props , list , parentStruct ) ; } } param relIndex param count param elemSize param struct param props param list param parentStruct protected createPropArray ( relIndex , count , elemSize , struct , props , list , parentStruct ) { const unsortedMap = new Map < number , string > ( ) ; for ( const prop of props ) { const relAddr = Labels . getNumberFromString64k ( struct + '.' + prop ) ; unsortedMap . set ( relAddr , prop ) ; } const sortedMap = new Map ( [ ... unsortedMap . entries ( ) ] . sort ( ( a , b ) => a [ 0 ] - b [ 0 ] ) ) ; sortedMap . set ( - 1 , '' ) ; let prevName ; let prevIndex ; let lastIndex = relIndex + elemSize ; for ( const [ index , name ] of sortedMap ) { if ( prevName ) { let len ; if ( name ) { len = index - prevIndex ; } else { len = lastIndex - prevIndex ; } const fullName = struct + '.' + prevName ; const subProps = Labels . getSubLabels ( fullName ) ; const memIndex = prevIndex ; const address = parentStruct . getAddress ( ) + memIndex ; const item = { address , elemSize : 0 , itemRef : 0 , indexedVariables : 0 } ; if ( subProps . length > 0 ) { item . itemRef = list . addObject ( new SubStructVar ( prevIndex , 1 , len , fullName , subProps , list , parentStruct ) ) ; } else { if ( len <= 2 ) { item . elemSize = len ; if ( len == 0 ) { item . itemRef = ( ) => { return '' ; } ; } else { item . itemRef = ( ) => { const mem = parentStruct . getMemory ( ) ; const value = Utility . getUintFromMemory ( mem , memIndex , len , this . littleEndian ) ; const result = Utility . getHexString ( value , 2 * len ) + 'h' ; return result ; } ; } } else { const memDumpVar = new MemDumpVar ( parentStruct . getAddress ( ) , elemSize , 1 , parentStruct . littleEndian ) ; memDumpVar . setParent ( parentStruct , memIndex ) ; item . itemRef = list . addObject ( memDumpVar ) ; item . indexedVariables = len ; } } this . propMap . set ( prevName , item ) ; } prevName = name ; prevIndex = index ; } } returns public async getContent ( start , count ) { const dbgVarArray = new Array < DebugProtocol . Variable > ( ) ; for ( const [ name , item ] of this . propMap ) { let value = '' ; let ref = 0 ; if ( typeof item . itemRef == 'number' ) { ref = item . itemRef ; } else { value = item . itemRef ( ) ; } const result = { name : name , type : Utility . getHexString ( item . address , 4 ) + 'h' , value , variablesReference : ref , indexedVariables : item . indexedVariables } ; dbgVarArray . push ( result ) ; } return dbgVarArray ; } param name param value returns public async setValue ( name , value ) { const item = this . propMap . get ( name ) ! ; if ( typeof item . itemRef == 'number' ) return '' ; const address = item . address ; const dataWrite = new Uint8Array ( item . elemSize ) ; Utility . setUintToMemory ( value , dataWrite , 0 , item . elemSize , this . littleEndian ) ; await Remote . writeMemoryDump ( address , dataWrite ) ; ShallowVar . memoryChanged = true ; const data = await Remote . readMemoryDump ( address , item . elemSize ) ; let readValue = Utility . getUintFromMemory ( data , 0 , item . elemSize , this . littleEndian ) ; const formattedString = Utility . numberFormatted ( name , readValue , item . elemSize , this . formatString ( item . elemSize ) , undefined ) ; return formattedString ; } /**
     * The format to use.
     */ protected formatString ( elemSize ) { if ( elemSize == 1 ) return Settings . launch . formatting . watchByte ; else return Settings . launch . formatting . watchWord ; } } /**
 * The StructVar class is a container class which holds other properties (the elements of the
 * struct). I.e. SubStructVars.
 * The StructVar is the parent object which also holds the memory contents.
 * The SubStructVars refer to it.
 */ export class StructVar extends SubStructVar { protected memory : Uint8Array ; protected baseAddress : number ; protected countBytes : number ; param addr param count param size param struct param props param parentStruct param list param littleEndian public constructor ( addr , count , size , struct , props , list , littleEndian = true ) { super ( 0 , count , size , struct , props , list ) ; this . baseAddress = addr ; this . littleEndian = littleEndian ; this . createPropArray ( 0 , count , size , struct , props , list , undefined as any ) ; this . countBytes = count * size ; } param relIndex param count param elemSize param struct param props param list param parentStruct protected createPropArray ( relIndex , count , elemSize , struct , props , list , parentStruct ) { if ( count <= 1 ) { super . createPropArray ( relIndex , count , elemSize , struct , props , list , this ) ; } else { let relIndex = 0 ; for ( let i = 0 ; i < count ; i ++ ) { let labelVar ; const address = this . getAddress ( ) + i * elemSize ; const name = '[' + i + ']' ; const item = { address , elemSize : 0 , itemRef : 0 , indexedVariables : 0 } ; if ( props . length ) { labelVar = new SubStructVar ( relIndex , 1 , elemSize , struct , props , list , this ) ; } else { labelVar = new MemDumpVar ( this . getAddress ( ) , elemSize , 1 , this . littleEndian ) ; labelVar . setParent ( this , relIndex ) ; item . indexedVariables = elemSize ; } item . itemRef = list . addObject ( labelVar ) ; this . propMap . set ( name , item ) ; relIndex += elemSize ; } } } returns public async getContent ( start , count ) { this . memory = await Remote . readMemoryDump ( this . getAddress ( ) , this . countBytes ) ; return super . getContent ( start , count ) ; } /**
     * Returns the cached memory.
     */ public getMemory ( ) { return this . memory ; } /**
     * Returns the base address.
     */ public getAddress ( ) { return this . baseAddress ; } } /**
 * The MemDumpByteVar class knows how to retrieve a memory dump from remote.
 * It allows retrieval of byte and word arrays.
 */ export class MemDumpVar extends ShallowVar { protected addr : number ; protected totalCount : number ; protected elemSize : number ; protected parentStruct : StructVar ; protected memOffset : number ; protected littleEndian : boolean ; param addr param totalCount param elemSize param littleEndian public constructor ( addr , totalCount , elemSize , littleEndian = true ) { super ( ) ; this . addr = addr ; this . totalCount = totalCount ; this . elemSize = elemSize ; this . memOffset = 0 ; this . littleEndian = littleEndian ; } param parentStruct param memOffset public setParent ( parentStruct , memOffset ) { this . parentStruct = parentStruct ; this . memOffset = memOffset ; } param handler param start param count public async getContent ( start , count ) { start = start || 0 ; count = count || ( this . totalCount - start ) ; let addr = this . addr + start ; const elemSize = this . elemSize ; const memArray = new Array < DebugProtocol . Variable > ( ) ; const format = this . formatString ( ) ; let memory ; let offset = this . memOffset ; if ( this . parentStruct ) { memory = this . parentStruct . getMemory ( ) ; offset += elemSize * start ; } else { memory = await Remote . readMemoryDump ( addr , count * elemSize ) ; } const tabSizes = Utility . calculateTabSizes ( format , elemSize ) ; for ( let i = 0 ; i < count ; i ++ ) { const value = Utility . getUintFromMemory ( memory , offset + i * this . elemSize , this . elemSize , this . littleEndian ) ; const addr_i = addr + offset + i * elemSize ; const formatted = Utility . numberFormattedSync ( value , elemSize , format , false , undefined , undefined , tabSizes ) ; const descr = Utility . getHexString ( addr_i , 4 ) + 'h' ; memArray . push ( { name : "[" + ( start + i ) + "]" , type : descr , value : formatted , variablesReference : 0 } ) ; } return memArray ; } param name param value returns public async setValue ( name , value ) { const indexString = name . substr ( 1 , name . length - 2 ) ; const index = parseInt ( indexString ) ; const address = this . addr + this . memOffset + index * this . elemSize ; const dataWrite = new Uint8Array ( this . elemSize ) ; Utility . setUintToMemory ( value , dataWrite , 0 , this . elemSize , this . littleEndian ) ; for ( let i = 0 ; i < this . elemSize ; i ++ ) { dataWrite [ i ] = value & 0xFF ; value = value >>> 8 ; } await Remote . writeMemoryDump ( address , dataWrite ) ; ShallowVar . memoryChanged = true ; const data = await Remote . readMemoryDump ( address , this . elemSize ) ; const readValue = Utility . getUintFromMemory ( data , 0 , this . elemSize , this . littleEndian ) ; const formattedString = Utility . numberFormatted ( name , readValue , this . elemSize , this . formatString ( ) , undefined ) ; return formattedString ; } /**
     * The format to use.
     */ protected formatString ( ) { if ( this . elemSize == 1 ) return Settings . launch . formatting . watchByte ; else return Settings . launch . formatting . watchWord ; } } /**
 * Represents an immediate value.
 * This has no reference to a variable but directly checks the memory contents.
 * It may be included in the returned item from the debug adapter 'evaluateLabelExpression'.
 * It's been used by the ContainerVar.
 */ export class ImmediateMemoryValue { protected address64k : number ; protected size : number ; protected littleEndian : boolean ; param addr64k param size param littleEndian constructor ( addr64k , size , littleEndian = true ) { if ( size > 6 ) throw Error ( 'The size of an element must be smaller than 7.' ) ; this . address64k = addr64k ; this . size = size ; this . littleEndian = littleEndian ; } returns public async getValue ( ) { const memory = await Remote . readMemoryDump ( this . address64k , this . size ) ; const memVal = Utility . getUintFromMemory ( memory , 0 , this . size , this . littleEndian ) ; return Utility . numberFormatted ( '' , memVal , this . size , this . formatString ( ) , undefined ) ; } param value returns public async setValue ( value ) { const dataWrite = new Uint8Array ( this . size ) ; Utility . setUintToMemory ( value , dataWrite , 0 , this . size , this . littleEndian ) ; await Remote . writeMemoryDump ( this . address64k , dataWrite ) ; ShallowVar . memoryChanged = true ; const data = await Remote . readMemoryDump ( this . address64k , this . size ) ; const readValue = Utility . getUintFromMemory ( data , 0 , this . size , this . littleEndian ) ; const formattedString = Utility . numberFormatted ( '' , readValue , this . size , this . formatString ( ) , undefined ) ; return formattedString ; } /**
     * The format to use.
     */ protected formatString ( ) { switch ( this . size ) { case 1 : return Settings . launch . formatting . watchByte ; case 2 : return Settings . launch . formatting . watchWord ; default : return "${hex}h,\t${unsigned}u,\t${signed}i" ; } } }