Skip to content

Commit 89da569

Browse files
committed
Add debug log script
1 parent e61bf07 commit 89da569

File tree

7 files changed

+338
-20
lines changed

7 files changed

+338
-20
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
*.hex
66
/build/
77
/out/
8+
debug.json
89

910
/src/init.mlog
1011
/src/main.mlog

mod/src/main/kotlin/gay/object/mlogv32/ProcessorAccess.kt

Lines changed: 82 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ import kotlinx.serialization.Serializable
1313
import kotlinx.serialization.json.Json
1414
import mindustry.Vars
1515
import mindustry.gen.Building
16+
import mindustry.logic.LVar
1617
import mindustry.world.blocks.logic.LogicBlock.LogicBuild
18+
import mindustry.world.blocks.logic.MemoryBlock.MemoryBuild
1719
import mindustry.world.blocks.logic.MessageBlock.MessageBuild
1820
import mindustry.world.blocks.logic.SwitchBlock.SwitchBuild
1921
import 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
268285
sealed 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")
338380
data 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")
366422
data 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

pyproject.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies = [
1313
"pyperclip>=1.9.0",
1414
"riscof",
1515
"riscv-isac",
16+
"tqdm>=4.67.1",
1617
"typer>=0.15.4",
1718
]
1819

python/src/mlogv32/processor_access.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,16 @@ def dump(
5656
self._send_request(DumpRequest(path=path, address=address, bytes=bytes))
5757
return self._recv_response(SuccessResponse)
5858

59-
def start(self, wait: bool):
60-
self._send_request(StartRequest(wait=wait))
59+
def start(self, *, single_step: bool = False):
60+
self._send_request(StartRequest(single_step=single_step))
61+
return self._recv_response(SuccessResponse)
62+
63+
def wait(self, *, stopped: bool, paused: bool):
64+
self._send_request(WaitRequest(stopped=stopped, paused=paused))
65+
return self._recv_response(SuccessResponse)
66+
67+
def unpause(self):
68+
self._send_request(UnpauseRequest())
6169
return self._recv_response(SuccessResponse)
6270

6371
def stop(self):
@@ -95,6 +103,9 @@ def __exit__(self, *_: Any):
95103
class BaseModel(_BaseModel):
96104
model_config = ConfigDict(
97105
alias_generator=alias_generators.to_camel,
106+
validate_by_name=True,
107+
validate_by_alias=True,
108+
serialize_by_alias=True,
98109
)
99110

100111

@@ -112,7 +123,17 @@ class DumpRequest(BaseModel):
112123

113124
class StartRequest(BaseModel):
114125
type: Literal["start"] = "start"
115-
wait: bool
126+
single_step: bool
127+
128+
129+
class WaitRequest(BaseModel):
130+
type: Literal["wait"] = "wait"
131+
stopped: bool
132+
paused: bool
133+
134+
135+
class UnpauseRequest(BaseModel):
136+
type: Literal["unpause"] = "unpause"
116137

117138

118139
class StopRequest(BaseModel):
@@ -124,7 +145,13 @@ class StatusRequest(BaseModel):
124145

125146

126147
type Request = Annotated[
127-
FlashRequest | DumpRequest | StartRequest | StopRequest | StatusRequest,
148+
FlashRequest
149+
| DumpRequest
150+
| StartRequest
151+
| WaitRequest
152+
| UnpauseRequest
153+
| StopRequest
154+
| StatusRequest,
128155
Field(discriminator="type"),
129156
]
130157

@@ -137,8 +164,20 @@ class SuccessResponse(BaseModel):
137164
class StatusResponse(BaseModel):
138165
type: Literal["status"]
139166
running: bool
140-
pc: int | None
167+
paused: bool
141168
error_output: str
169+
pc: int | None
170+
instruction: int | None
171+
privilege_mode: int | None
172+
registers: list[int]
173+
mscratch: int
174+
mtvec: int
175+
mepc: int
176+
mcause: int
177+
mtval: int
178+
mstatus: int
179+
mip: int
180+
mie: int
142181

143182

144183
class ErrorResponse(BaseModel):

0 commit comments

Comments
 (0)