@@ -22,6 +22,7 @@ import {
22
22
StackFrame ,
23
23
StoppedEvent ,
24
24
TerminatedEvent ,
25
+ MemoryEvent ,
25
26
Thread ,
26
27
Variable ,
27
28
} from '@vscode/debugadapter'
@@ -134,6 +135,7 @@ const enum displayFormat {
134
135
hex = 'hex' ,
135
136
binary = 'binary' ,
136
137
decimal = 'decimal' ,
138
+ string = 'string' ,
137
139
}
138
140
139
141
// export class JSBeebDebugSession implements DebugAdapter {
@@ -271,6 +273,8 @@ export class JSBeebDebugSession extends LoggingDebugSession {
271
273
272
274
response . body . supportsSteppingGranularity = false
273
275
276
+ response . body . supportsReadMemoryRequest = true
277
+
274
278
this . sendResponse ( response )
275
279
276
280
// since this debug adapter can accept configuration requests like 'setBreakpoint' at any time,
@@ -605,7 +609,7 @@ export class JSBeebDebugSession extends LoggingDebugSession {
605
609
// eslint-disable-next-line @typescript-eslint/no-unused-vars
606
610
request ?: DebugProtocol . Request | undefined ,
607
611
) : Promise < void > {
608
- console . log ( args )
612
+ // console.log(args)
609
613
console . log ( `${ new Date ( ) . toLocaleTimeString ( ) } variablesRequest called` )
610
614
const variables : Variable [ ] = [ ]
611
615
if ( args . filter === undefined || args . filter === 'named' ) {
@@ -624,6 +628,12 @@ export class JSBeebDebugSession extends LoggingDebugSession {
624
628
[ 'Cycles' , 'Next op' ] . includes ( reg . name ) ,
625
629
)
626
630
variables . push ( ...system )
631
+ const memory : DebugProtocol . Variable = new Variable (
632
+ 'Memory' ,
633
+ 'Click icon to view' ,
634
+ )
635
+ memory . memoryReference = 'memory'
636
+ variables . push ( memory )
627
637
}
628
638
}
629
639
response . body = { variables : variables }
@@ -685,6 +695,46 @@ export class JSBeebDebugSession extends LoggingDebugSession {
685
695
return vars
686
696
}
687
697
698
+ protected async readMemoryRequest (
699
+ response : DebugProtocol . ReadMemoryResponse ,
700
+ { memoryReference, offset = 0 , count } : DebugProtocol . ReadMemoryArguments ,
701
+ ) : Promise < void > {
702
+ console . log ( `${ new Date ( ) . toLocaleTimeString ( ) } readMemoryRequest called` )
703
+ // console.log({ memoryReference, offset, count })
704
+ if ( memoryReference === 'memory' && count !== 0 ) {
705
+ if ( offset > this . memory . length ) {
706
+ response . body = {
707
+ address : offset . toString ( ) ,
708
+ unreadableBytes : count ,
709
+ data : '' ,
710
+ }
711
+ } else {
712
+ const unreadableBytes = Math . max ( offset + count - this . memory . length , 0 )
713
+ response . body = {
714
+ address : offset . toString ( ) ,
715
+ unreadableBytes : unreadableBytes ,
716
+ data : this . convertMemoryToBase64 ( offset , count - unreadableBytes ) ,
717
+ }
718
+ }
719
+ } else {
720
+ response . body = {
721
+ address : offset . toString ( ) ,
722
+ unreadableBytes : 0 ,
723
+ data : '' ,
724
+ }
725
+ }
726
+ this . sendResponse ( response )
727
+ }
728
+
729
+ private convertMemoryToBase64 ( offset : number , count : number ) : string {
730
+ if ( count == 0 ) {
731
+ count = this . memory . length - offset
732
+ }
733
+ return Buffer . from ( this . memory . slice ( offset , offset + count ) ) . toString (
734
+ 'base64' ,
735
+ )
736
+ }
737
+
688
738
protected async stackTraceRequest (
689
739
response : DebugProtocol . StackTraceResponse ,
690
740
args : DebugProtocol . StackTraceArguments ,
@@ -727,6 +777,8 @@ export class JSBeebDebugSession extends LoggingDebugSession {
727
777
current = current . parent
728
778
}
729
779
this . sendResponse ( response )
780
+ // Since we refreshed the memory, emit a MemoryEvent
781
+ this . sendEvent ( new MemoryEvent ( 'memory' , 0 , this . memory . length ) )
730
782
}
731
783
// console.log(response)
732
784
}
@@ -737,8 +789,11 @@ export class JSBeebDebugSession extends LoggingDebugSession {
737
789
// eslint-disable-next-line @typescript-eslint/no-unused-vars
738
790
request ?: DebugProtocol . Request ,
739
791
) : Promise < void > {
740
- console . log ( args )
741
- const validExp = / ( [ $ & % . ] | \. \* | \. \^ ) ? ( [ a - z ] [ a - z 0 - 9 _ ] * ) ( \. [ w d ] ) ? / gi
792
+ console . log (
793
+ `${ new Date ( ) . toLocaleTimeString ( ) } evaluateRequest '${ args . expression } '` ,
794
+ )
795
+ const validExp =
796
+ / ( [ $ & % . ] | \. \* | \. \^ ) ? ( [ a - z ] [ a - z 0 - 9 _ ] * | \( [ $ & ] [ 0 - 9 a - f ] + \) | \( [ 0 - 9 ] + \) ) ( \. [ w d ] | \. s [ 0 - 9 ] + ) ? / gi
742
797
if ( args . context === 'watch' ) {
743
798
const match = validExp . exec ( args . expression )
744
799
if ( match === null ) {
@@ -747,7 +802,7 @@ export class JSBeebDebugSession extends LoggingDebugSession {
747
802
}
748
803
const formatPrefix = match [ 1 ] ?? ''
749
804
let label = match [ 2 ]
750
- const sizeSuffix = match [ 3 ] ?? 'b'
805
+ const sizeSuffix = ( match [ 3 ] ?? '.b' ) . toLowerCase ( )
751
806
let format : displayFormat
752
807
switch ( formatPrefix ) {
753
808
case '&' :
@@ -774,12 +829,14 @@ export class JSBeebDebugSession extends LoggingDebugSession {
774
829
case '.d' :
775
830
bytes = 4
776
831
break
777
- default :
832
+ case '.b' :
778
833
bytes = 1
779
834
break
835
+ default :
836
+ format = displayFormat . string
837
+ bytes = parseInt ( sizeSuffix . slice ( 2 ) , 10 )
838
+ break
780
839
}
781
- // TODO - consider adding ".s" suffix for strings
782
- // TODO - maybe signed/unsigned variants? Big/little endian?
783
840
784
841
// search for label in labels list after removing prefix if necessary
785
842
if ( label . startsWith ( '.' ) ) {
@@ -790,7 +847,8 @@ export class JSBeebDebugSession extends LoggingDebugSession {
790
847
}
791
848
if (
792
849
this . labelMap [ '.' + label ] === undefined &&
793
- this . symbolMap [ label ] === undefined
850
+ this . symbolMap [ label ] === undefined &&
851
+ ! label . startsWith ( '(' )
794
852
) {
795
853
this . sendErrorResponse ( response , 0 , '' )
796
854
return
@@ -805,7 +863,13 @@ export class JSBeebDebugSession extends LoggingDebugSession {
805
863
}
806
864
807
865
let address : number
808
- if ( this . labelMap [ '.' + label ] !== undefined ) {
866
+ if ( label . startsWith ( '(' ) ) {
867
+ if ( label . charAt ( 1 ) === '&' || label . charAt ( 1 ) === '$' ) {
868
+ address = parseInt ( label . slice ( 2 , - 1 ) , 16 )
869
+ } else {
870
+ address = parseInt ( label . slice ( 1 , - 1 ) , 10 )
871
+ }
872
+ } else if ( this . labelMap [ '.' + label ] !== undefined ) {
809
873
address = this . labelMap [ '.' + label ]
810
874
} else {
811
875
address = this . symbolMap [ label ]
@@ -828,6 +892,10 @@ export class JSBeebDebugSession extends LoggingDebugSession {
828
892
. padStart ( 2 * bytes , '0' ) } `
829
893
} else if ( format === displayFormat . binary ) {
830
894
displayValue = `%${ value . toString ( 2 ) . padStart ( 8 * bytes , '0' ) } `
895
+ } else if ( format === displayFormat . string ) {
896
+ displayValue = String . fromCharCode (
897
+ ...this . memory . slice ( address , address + bytes ) ,
898
+ )
831
899
} else {
832
900
displayValue = `${ value } `
833
901
}
0 commit comments