@@ -13,7 +13,9 @@ import kotlinx.serialization.Serializable
1313import kotlinx.serialization.json.Json
1414import mindustry.Vars
1515import mindustry.gen.Building
16+ import mindustry.logic.LVar
1617import mindustry.world.blocks.logic.LogicBlock.LogicBuild
18+ import mindustry.world.blocks.logic.MemoryBlock.MemoryBuild
1719import mindustry.world.blocks.logic.MessageBlock.MessageBuild
1820import mindustry.world.blocks.logic.SwitchBlock.SwitchBuild
1921import kotlin.concurrent.thread
@@ -27,8 +29,12 @@ class ProcessorAccess(
2729 val memoryWidth : Int ,
2830 val romSize : Int ,
2931 val ramSize : Int ,
32+ val registers : MemoryBuild ,
33+ val csrs : LogicBuild ,
3034 val errorOutput : MessageBuild ,
3135 val resetSwitch : SwitchBuild ,
36+ val pauseSwitch : SwitchBuild ,
37+ val singleStepSwitch : SwitchBuild ,
3238) {
3339 val romEnd = ROM_START + romSize.toUInt()
3440 val ramEnd = RAM_START + ramSize.toUInt()
@@ -116,6 +122,11 @@ class ProcessorAccess(
116122 ProcessorAccess .stopServer()
117123 }
118124
125+ fun getCSR (address : Int ): UInt =
126+ csrs.executor.optionalVar(address + 1 )
127+ ?.numu()
128+ ? : 0u
129+
119130 private fun ramWordsSequence (startAddress : UInt ) = sequence {
120131 require(startAddress in RAM_START .. < ramEnd) { " Start address must be within RAM." }
121132 require(startAddress.mod(4u ) == 0u ) { " Start address must be aligned to 4 bytes." }
@@ -230,8 +241,12 @@ class ProcessorAccess(
230241 memoryWidth = positiveIntVar(build, " MEMORY_WIDTH" ) ? : return null ,
231242 romSize = positiveIntVar(build, " ROM_SIZE" ) ? : return null ,
232243 ramSize = positiveIntVar(build, " RAM_SIZE" ) ? : return null ,
244+ registers = buildVar<MemoryBuild >(build, " cell1" ) ? : return null ,
245+ csrs = buildVar<LogicBuild >(build, " processor17" ) ? : return null ,
233246 errorOutput = buildVar<MessageBuild >(build, " message1" ) ? : return null ,
234247 resetSwitch = buildVar<SwitchBuild >(build, " switch1" ) ? : return null ,
248+ pauseSwitch = buildVar<SwitchBuild >(build, " switch2" ) ? : return null ,
249+ singleStepSwitch = buildVar<SwitchBuild >(build, " switch3" ) ? : return null ,
235250 )
236251 }
237252
@@ -264,6 +279,8 @@ private fun linkedBuild(build: LogicBuild, name: String) =
264279 .firstOrNull { it.active && it.valid && it.name == name }
265280 ?.let { Vars .world.build(it.x, it.y) }
266281
282+ private fun LVar.numu () = num().toUInt()
283+
267284@Serializable
268285sealed class Request {
269286 abstract suspend fun handle (processor : ProcessorAccess ): Response
@@ -283,7 +300,9 @@ sealed class Request {
283300
284301@Serializable
285302@SerialName(" flash" )
286- data class FlashRequest (val path : String ) : Request() {
303+ data class FlashRequest (
304+ val path : String ,
305+ ) : Request() {
287306 override suspend fun handle (processor : ProcessorAccess ) = runOnMainThread {
288307 val file = Core .files.absolute(path)
289308 require(file.exists()) { " File not found." }
@@ -314,30 +333,55 @@ data class DumpRequest(
314333
315334@Serializable
316335@SerialName(" start" )
317- data class StartRequest (val wait : Boolean ) : Request() {
318- override suspend fun handle (processor : ProcessorAccess ): Response {
319- runOnMainThread {
320- processor.resetSwitch.configure(false )
321- }
322- if (! wait) {
323- return SuccessResponse (" Processor started." )
324- }
336+ data class StartRequest (
337+ val singleStep : Boolean = false ,
338+ ) : Request() {
339+ override suspend fun handle (processor : ProcessorAccess ) = runOnMainThread {
340+ processor.singleStepSwitch.configure(singleStep)
341+ processor.resetSwitch.configure(false )
342+ SuccessResponse (" Processor started." )
343+ }
344+ }
325345
346+ @Serializable
347+ @SerialName(" wait" )
348+ data class WaitRequest (
349+ val stopped : Boolean ,
350+ val paused : Boolean ,
351+ ) : Request() {
352+ override suspend fun handle (processor : ProcessorAccess ): Response {
326353 while (true ) {
327354 delay(1000 / 60 ) // 1 tick
328- val stopped = runOnMainThread { processor.resetSwitch.enabled }
329- if (stopped) {
330- return SuccessResponse (" Processor started and finished executing." )
355+ val (stopped, paused) = runOnMainThread {
356+ processor.resetSwitch.enabled to processor.pauseSwitch.enabled
357+ }
358+ if (this .stopped && stopped) {
359+ return SuccessResponse (" Processor has stopped." )
360+ }
361+ if (this .paused && paused) {
362+ return SuccessResponse (" Processor has paused." )
331363 }
332364 }
333365 }
334366}
335367
368+ @Serializable
369+ @SerialName(" unpause" )
370+ data object UnpauseRequest : Request () {
371+ override suspend fun handle (processor : ProcessorAccess ) = runOnMainThread {
372+ require(! processor.resetSwitch.enabled) { " Processor is not running!" }
373+ processor.pauseSwitch.configure(false )
374+ SuccessResponse (" Processor unpaused." )
375+ }
376+ }
377+
336378@Serializable
337379@SerialName(" stop" )
338380data object StopRequest : Request () {
339381 override suspend fun handle (processor : ProcessorAccess ) = runOnMainThread {
340382 processor.resetSwitch.configure(true )
383+ processor.pauseSwitch.configure(false )
384+ processor.singleStepSwitch.configure(false )
341385 SuccessResponse (" Processor stopped." )
342386 }
343387}
@@ -348,8 +392,20 @@ data object StatusRequest : Request() {
348392 override suspend fun handle (processor : ProcessorAccess ) = runOnMainThread {
349393 StatusResponse (
350394 running = ! processor.resetSwitch.enabled,
351- pc = processor.build.executor.optionalVar( " pc " )?.numi() ,
395+ paused = processor.pauseSwitch.enabled ,
352396 errorOutput = processor.errorOutput.message?.toString() ? : " " ,
397+ pc = processor.build.executor.optionalVar(" pc" )?.numu(),
398+ instruction = processor.build.executor.optionalVar(" instruction" )?.numu(),
399+ privilegeMode = processor.build.executor.optionalVar(" privilege_mode" )?.numu(),
400+ registers = processor.registers.memory.take(32 ).map { it.toUInt() },
401+ mscratch = processor.getCSR(0x340 ),
402+ mtvec = processor.getCSR(0x305 ),
403+ mepc = processor.getCSR(0x341 ),
404+ mcause = processor.getCSR(0x342 ),
405+ mtval = processor.getCSR(0x343 ),
406+ mstatus = processor.getCSR(0x300 ),
407+ mip = processor.getCSR(0x344 ),
408+ mie = processor.getCSR(0x304 ),
353409 )
354410 }
355411}
@@ -365,8 +421,20 @@ data class SuccessResponse(val message: String) : Response()
365421@SerialName(" status" )
366422data class StatusResponse (
367423 val running : Boolean ,
368- val pc : Int? ,
424+ val paused : Boolean ,
369425 val errorOutput : String ,
426+ val pc : UInt? ,
427+ val instruction : UInt? ,
428+ val privilegeMode : UInt? ,
429+ val registers : List <UInt >,
430+ val mscratch : UInt ,
431+ val mtvec : UInt ,
432+ val mepc : UInt ,
433+ val mcause : UInt ,
434+ val mtval : UInt ,
435+ val mstatus : UInt ,
436+ val mip : UInt ,
437+ val mie : UInt ,
370438) : Response()
371439
372440@Serializable
0 commit comments