Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

144 wiersze
5.4KB

  1. # Shared helpers for the sequential Nova128 editor/compiler launchers (E07-S02).
  2. # Import-Module (Join-Path $PSScriptRoot "lib\Nova128Launcher.psm1") -Force
  3. $script:ViceBin = "C:\Program Files\GTK3VICE-3.10-win64\bin"
  4. function Get-Nova128ViceTool([string]$Name) {
  5. $path = Join-Path $script:ViceBin "$Name.exe"
  6. if (-not (Test-Path -LiteralPath $path)) { throw "$Name.exe not found at $path" }
  7. return $path
  8. }
  9. # One writable session per image directory. The lock holds the owning PID and
  10. # kind; a lock whose process is gone is stale and is replaced.
  11. function Enter-Nova128ImageSession {
  12. param(
  13. [Parameter(Mandatory)][string]$Image,
  14. [Parameter(Mandatory)][ValidateSet("editor", "compiler")][string]$Kind
  15. )
  16. $folder = Split-Path ([IO.Path]::GetFullPath($Image)) -Parent
  17. New-Item -ItemType Directory -Force -Path $folder | Out-Null
  18. $lockPath = Join-Path $folder ".newlang-session.lock"
  19. if (Test-Path -LiteralPath $lockPath) {
  20. # A live holder keeps the file open without sharing, so even reading it
  21. # can fail. That is the same answer as a readable live PID.
  22. $text = ""
  23. try {
  24. $text = Get-Content -Raw -LiteralPath $lockPath
  25. } catch {
  26. throw "another Nova128 session already holds $Image"
  27. }
  28. $owner = 0
  29. $ownerKind = "another"
  30. if ($text -match '(?m)^(\d+)\s+(\S+)') {
  31. $owner = [int]$Matches[1]
  32. $ownerKind = $Matches[2]
  33. }
  34. $alive = $owner -gt 0 -and $null -ne (Get-Process -Id $owner -ErrorAction SilentlyContinue)
  35. if ($alive) {
  36. throw "the $ownerKind session (pid $owner) still owns $Image; close it before starting another"
  37. }
  38. Remove-Item -LiteralPath $lockPath -Force
  39. }
  40. try {
  41. $stream = [IO.File]::Open($lockPath, [IO.FileMode]::CreateNew,
  42. [IO.FileAccess]::Write, [IO.FileShare]::None)
  43. } catch {
  44. throw "another Nova128 session already holds $Image"
  45. }
  46. $writer = [IO.StreamWriter]::new($stream)
  47. $writer.WriteLine("$PID $Kind")
  48. $writer.Flush()
  49. return [pscustomobject]@{ Path = $lockPath; Stream = $stream; Writer = $writer
  50. Image = $Image; Kind = $Kind }
  51. }
  52. function Exit-Nova128ImageSession {
  53. param([Parameter(Mandatory)]$Session)
  54. try {
  55. $Session.Writer.Dispose()
  56. $Session.Stream.Dispose()
  57. } finally {
  58. if (Test-Path -LiteralPath $Session.Path) {
  59. Remove-Item -LiteralPath $Session.Path -Force
  60. }
  61. if ($Session.Image) {
  62. Wait-Nova128ImageFlush -Image $Session.Image
  63. }
  64. }
  65. }
  66. # The emulator has exited, but DOS writes may still be in flight. Return only
  67. # when the image can be opened exclusively.
  68. function Wait-Nova128ImageFlush {
  69. param(
  70. [Parameter(Mandatory)][string]$Image,
  71. [int]$TimeoutSeconds = 30
  72. )
  73. if (-not (Test-Path -LiteralPath $Image)) { return }
  74. $deadline = [DateTime]::UtcNow.AddSeconds($TimeoutSeconds)
  75. while ($true) {
  76. try {
  77. $stream = [IO.File]::Open($Image, [IO.FileMode]::Open,
  78. [IO.FileAccess]::Read, [IO.FileShare]::None)
  79. $stream.Dispose()
  80. return
  81. } catch {
  82. if ([DateTime]::UtcNow -ge $deadline) {
  83. throw "the emulator exited but $Image is still locked (image not flushed)"
  84. }
  85. Start-Sleep -Milliseconds 200
  86. }
  87. }
  88. }
  89. # Start an emulator and wait for it to exit. Autostart uses the host program
  90. # path, so the program is deterministic; the disk image stays attached for the
  91. # session's own reads and writes.
  92. function Invoke-Nova128Emulator {
  93. param(
  94. [Parameter(Mandatory)][ValidateSet("x64sc", "x128")][string]$Emulator,
  95. [Parameter(Mandatory)][string]$Program,
  96. [string]$DiskImage,
  97. [string]$Screenshot,
  98. [int]$LimitCycles = 0,
  99. [switch]$Warp
  100. )
  101. $tool = Get-Nova128ViceTool $Emulator
  102. if (-not (Test-Path -LiteralPath $Program)) { throw "program not found: $Program" }
  103. $arguments = @()
  104. if ($DiskImage) {
  105. if (-not (Test-Path -LiteralPath $DiskImage)) {
  106. throw "disk image not found: $DiskImage"
  107. }
  108. $arguments += @("-drive8type", "1581", "-drive8truedrive", "-8",
  109. ('"' + $DiskImage + '"'))
  110. }
  111. $arguments += @("-autostart", ('"' + $Program + '"'), "-autostart-warp",
  112. "-sounddev", "dummy")
  113. if ($Warp) { $arguments += "-warp" }
  114. if ($LimitCycles -gt 0) { $arguments += @("-limitcycles", "$LimitCycles") }
  115. if ($Screenshot) {
  116. if (Test-Path -LiteralPath $Screenshot) {
  117. Remove-Item -LiteralPath $Screenshot -Force
  118. }
  119. # x64sc names the VIC-II exit screenshot differently from x128.
  120. $shotOption = if ($Emulator -eq "x64sc") { "-exitscreenshot" } else { "-exitscreenshotvicii" }
  121. $arguments += @($shotOption, ('"' + $Screenshot + '"'))
  122. }
  123. Write-Host ("launching {0} with {1}" -f $Emulator, $Program)
  124. $process = Start-Process -FilePath $tool -ArgumentList $arguments -PassThru -Wait
  125. if ($Screenshot -and -not (Test-Path -LiteralPath $Screenshot)) {
  126. throw "$Emulator did not create the exit screenshot $Screenshot"
  127. }
  128. if ($DiskImage) { Wait-Nova128ImageFlush -Image $DiskImage }
  129. return $process.ExitCode
  130. }
  131. Export-ModuleMember -Function Get-Nova128ViceTool, Enter-Nova128ImageSession,
  132. Exit-Nova128ImageSession, Wait-Nova128ImageFlush, Invoke-Nova128Emulator

Powered by TurnKey Linux.