Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

189 rindas
7.8KB

  1. # E01-S02: execute the MMU probe and verify its machine-readable result block.
  2. [CmdletBinding()]
  3. param([int]$RemotePort = 6511)
  4. $ErrorActionPreference = "Stop"
  5. $project = Split-Path $PSScriptRoot -Parent
  6. $build = Join-Path $project "build"
  7. $program = Join-Path $build "mmu-probe.prg"
  8. $labelsPath = Join-Path $build "mmu-probe.lbl"
  9. $traceCommands = Join-Path $project "monitor\mmu-probe-trace.txt"
  10. $monitorLog = Join-Path $build "mmu-probe-monitor.log"
  11. $x128 = "C:\Program Files\GTK3VICE-3.10-win64\bin\x128.exe"
  12. & (Join-Path $PSScriptRoot "build-mmu-probe.ps1")
  13. if ($LASTEXITCODE -ne 0) { throw "MMU probe build failed" }
  14. if (Test-Path -LiteralPath $monitorLog) { Remove-Item -LiteralPath $monitorLog -Force }
  15. $labelText = Get-Content -Raw -LiteralPath $labelsPath
  16. function Get-LabelAddress([string]$name) {
  17. $match = [regex]::Match($labelText,
  18. "(?im)^al\s+([0-9a-f]+)\s+\." + [regex]::Escape($name) + "\s*$")
  19. if (-not $match.Success) { throw "missing label $name" }
  20. return [Convert]::ToInt32($match.Groups[1].Value, 16)
  21. }
  22. $resultAddress = Get-LabelAddress "mmu_probe_result"
  23. $completeAddress = Get-LabelAddress "mmu_probe_complete"
  24. $bank0Address = Get-LabelAddress "mmu_probe_observed_bank0"
  25. $bank1Address = Get-LabelAddress "mmu_probe_observed_bank1"
  26. $p0Address = Get-LabelAddress "mmu_probe_observed_p0"
  27. $p1Address = Get-LabelAddress "mmu_probe_observed_p1"
  28. $p0cBank0Address = Get-LabelAddress "mmu_probe_obs_p0c_b0"
  29. $p1cBank0Address = Get-LabelAddress "mmu_probe_obs_p1c_b0"
  30. $stateEndAddress = Get-LabelAddress "mmu_probe_common_rcr"
  31. $entryAddress = Get-LabelAddress "mmu_probe_entry"
  32. $doneAddress = Get-LabelAddress "mmu_probe_done"
  33. $codeEndAddress = Get-LabelAddress "mmu_probe_code_end"
  34. # The checked-in trace file has the fixed entry point; the done address moves
  35. # with the code, so append it from the fresh label file.
  36. $generatedTrace = Join-Path $build "mmu-probe-trace.gen.txt"
  37. $traceText = (Get-Content -Raw -LiteralPath $traceCommands) +
  38. ("trace exec `${0:X4}`ncommand 4 `"disable 2`"`n" -f $doneAddress)
  39. [IO.File]::WriteAllText($generatedTrace, $traceText, [Text.Encoding]::ASCII)
  40. $traceCommands = $generatedTrace
  41. $arguments = @(
  42. "-autostart", ('"' + $program + '"'),
  43. "-autostart-warp", "-warp", "-sounddev", "dummy",
  44. "-moncommands", ('"' + $traceCommands + '"'),
  45. "-monlog", "-monlogname", ('"' + $monitorLog + '"'),
  46. "-remotemonitor", "-remotemonitoraddress", ("ip4://127.0.0.1:{0}" -f $RemotePort)
  47. ) -join ' '
  48. $psi = [Diagnostics.ProcessStartInfo]::new()
  49. $psi.FileName = $x128
  50. $psi.Arguments = $arguments
  51. $psi.UseShellExecute = $true
  52. $psi.WindowStyle = [Diagnostics.ProcessWindowStyle]::Hidden
  53. $process = [Diagnostics.Process]::Start($psi)
  54. $client = $null
  55. try {
  56. $deadline = [DateTime]::UtcNow.AddSeconds(10)
  57. while ([DateTime]::UtcNow -lt $deadline) {
  58. if ($process.HasExited) { throw "x128 exited before remote verification" }
  59. try {
  60. $client = [Net.Sockets.TcpClient]::new()
  61. $client.Connect("127.0.0.1", $RemotePort)
  62. break
  63. } catch {
  64. if ($client) { $client.Dispose(); $client = $null }
  65. Start-Sleep -Milliseconds 200
  66. }
  67. }
  68. if (-not $client -or -not $client.Connected) {
  69. throw "could not connect to VICE remote monitor"
  70. }
  71. Start-Sleep -Seconds 3
  72. $stream = $client.GetStream()
  73. $stream.ReadTimeout = 2000
  74. $writer = [IO.StreamWriter]::new($stream, [Text.Encoding]::ASCII, 1024, $true)
  75. $writer.NewLine = "`n"
  76. $writer.AutoFlush = $true
  77. $writer.WriteLine(("m `${0:X4} `${1:X4}" -f $resultAddress, $stateEndAddress))
  78. Start-Sleep -Milliseconds 400
  79. $buffer = New-Object byte[] 16384
  80. $response = ""
  81. while ($stream.DataAvailable) {
  82. $count = $stream.Read($buffer, 0, $buffer.Length)
  83. if ($count -le 0) { break }
  84. $response += [Text.Encoding]::ASCII.GetString($buffer, 0, $count)
  85. Start-Sleep -Milliseconds 50
  86. }
  87. $expected = @(
  88. @{ Address = $resultAddress; Value = 0xFF; Name = "result" },
  89. @{ Address = $completeAddress; Value = 0xA5; Name = "complete" },
  90. @{ Address = $bank0Address; Value = 0x11; Name = "bank0" },
  91. @{ Address = $bank1Address; Value = 0x22; Name = "bank1" },
  92. @{ Address = $p0Address; Value = 0x77; Name = "page0" },
  93. @{ Address = $p1Address; Value = 0x33; Name = "page1" },
  94. @{ Address = $p0cBank0Address; Value = 0x66; Name = "page0-common-bank0" },
  95. @{ Address = $p1cBank0Address; Value = 0x5A; Name = "page1-common-bank0" }
  96. )
  97. # Parse every monitor dump row into address -> byte so checks do not
  98. # depend on where a 16-byte row happens to start.
  99. $memory = @{}
  100. $rows = [regex]::Matches($response,
  101. "(?i)C:([0-9a-f]{4})((?:[ ]{1,2}[0-9a-f]{2}){1,16})")
  102. foreach ($row in $rows) {
  103. $address = [Convert]::ToInt32($row.Groups[1].Value, 16)
  104. foreach ($hex in ($row.Groups[2].Value.Trim() -split '\s+')) {
  105. $memory[$address] = [Convert]::ToInt32($hex, 16)
  106. $address++
  107. }
  108. }
  109. foreach ($item in $expected) {
  110. if (-not $memory.ContainsKey($item.Address) -or
  111. $memory[$item.Address] -ne $item.Value) {
  112. throw ("{0} at `${1:X4} was not `${2:X2}; monitor response: {3}" -f
  113. $item.Name, $item.Address, $item.Value, $response)
  114. }
  115. }
  116. $writer.WriteLine("q")
  117. $writer.Dispose()
  118. $client.Dispose()
  119. $client = $null
  120. if (-not $process.WaitForExit(5000)) { throw "x128 did not exit after monitor quit" }
  121. if (-not (Test-Path -LiteralPath $monitorLog)) { throw "monitor log not created" }
  122. # Trace hits go to the log before the remote client connects and to the
  123. # remote stream afterwards; examine both.
  124. $trace = (Get-Content -Raw -LiteralPath $monitorLog) + "`n" + $response
  125. [IO.File]::WriteAllText((Join-Path $build "mmu-probe-trace-dump.txt"), $trace)
  126. # Every hit is "#n (Trace <kind> <addr>) ..." followed by ".C:<pc> ...".
  127. $hits = [regex]::Matches($trace,
  128. "(?im)^#\d+ \(Trace\s+(exec|store) ([0-9a-f]{4})\)[^\r\n]*\r?\n\.C:([0-9a-f]{4})")
  129. $inWindow = $false
  130. $windowClosed = $false
  131. $storeCount = 0
  132. $written = @{}
  133. foreach ($hit in $hits) {
  134. $kind = $hit.Groups[1].Value.ToLowerInvariant()
  135. $target = [Convert]::ToInt32($hit.Groups[2].Value, 16)
  136. $pc = [Convert]::ToInt32($hit.Groups[3].Value, 16)
  137. if ($kind -eq 'exec') {
  138. if ($target -eq $entryAddress -and -not $windowClosed) { $inWindow = $true }
  139. elseif ($target -eq $doneAddress -and $inWindow) {
  140. $inWindow = $false; $windowClosed = $true; break
  141. }
  142. continue
  143. }
  144. if (-not $inWindow) { continue }
  145. if ($pc -lt $entryAddress -or $pc -ge $codeEndAddress) {
  146. throw ("MMU store to `${0:X4} from `${1:X4}, outside probe code" -f $target, $pc)
  147. }
  148. $written[$target] = $true
  149. $storeCount++
  150. }
  151. if (-not $windowClosed) { throw "trace has no complete entry..done probe window" }
  152. foreach ($register in @(0xFF00, 0xD506, 0xD507, 0xD508, 0xD509, 0xD50A)) {
  153. if (-not $written.ContainsKey($register)) {
  154. throw ("probe window has no store to `${0:X4}" -f $register)
  155. }
  156. }
  157. foreach ($register in @(0xD500, 0xD501, 0xD502, 0xD503, 0xD504, 0xD505, 0xD50B)) {
  158. if ($written.ContainsKey($register)) {
  159. throw ("probe wrote unintended MMU register `${0:X4}" -f $register)
  160. }
  161. }
  162. Write-Host ("verified {0} MMU stores in the probe window, all from probe code" -f $storeCount)
  163. Write-Host ("verified MMU result `$FF, completion `$A5, banks `$11/`$22, " +
  164. "pages `$77/`$33, common-priority bank0 `$66/`$5A")
  165. Write-Host ("monitor log: {0}" -f $monitorLog)
  166. } finally {
  167. if ($client) { $client.Dispose() }
  168. if ($process -and -not $process.HasExited) {
  169. $process.Kill()
  170. $process.WaitForExit()
  171. }
  172. }

Powered by TurnKey Linux.