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.

202 wiersze
9.8KB

  1. # E07-S05: drive build/n128c.prg through scripts/launch-compiler.ps1 on a fresh
  2. # development image and check the PRG, MAP, ERR and summary it produces.
  3. #
  4. # success COUNTER.N8 -> COUNTER.PRG + COUNTER.MAP, no ERR, summary on screen
  5. # failure BAD.N8 -> BAD.ERR, no BAD.PRG/BAD.MAP, earlier outputs intact
  6. # collision COUNTER.N8 -> OUTPUT EXISTS, COUNTER.PRG byte-identical
  7. # run the generated COUNTER.PRG reports MB_ST_PASS in a second session
  8. [CmdletBinding()]
  9. param([int]$Port = 6552, [int]$TimeoutSeconds = 240)
  10. $ErrorActionPreference = "Stop"
  11. $project = Split-Path $PSScriptRoot -Parent
  12. Import-Module (Join-Path $PSScriptRoot "lib\Nova128Test.psm1") -Force
  13. & (Join-Path $PSScriptRoot "build-driver.ps1") | Out-Host
  14. $root = Join-Path $project "build\driver-test"
  15. if (Test-Path -LiteralPath $root) { Remove-Item -LiteralPath $root -Recurse -Force }
  16. New-Item -ItemType Directory -Force -Path $root | Out-Null
  17. $driver = Join-Path $project "build\n128c.prg"
  18. $work = Join-Path $root "work.d81"
  19. $c1541 = Get-ViceTool "c1541"
  20. $failures = @()
  21. # 0: prepare-disk.ps1 injects exactly the build the driver was made from.
  22. $prepared = Join-Path $root "prepared.d81"
  23. & (Join-Path $PSScriptRoot "prepare-disk.ps1") -OutputImage $prepared `
  24. -CompilerPrg $driver -RequireCompiler | Out-Host
  25. $injectedPath = Join-Path $root "prepared-n128c"
  26. & $c1541 $prepared -read "n128c" $injectedPath 2>&1 | Out-Null
  27. if (-not (Test-Path -LiteralPath $injectedPath)) {
  28. $failures += "prepare-disk.ps1 did not inject n128c"
  29. } elseif ([Convert]::ToBase64String([IO.File]::ReadAllBytes($injectedPath)) -ne
  30. [Convert]::ToBase64String([IO.File]::ReadAllBytes($driver))) {
  31. $failures += "prepare-disk.ps1 injected a different n128c"
  32. }
  33. $counterPet = Join-Path $root "counter.pet"
  34. [IO.File]::WriteAllBytes($counterPet, (ConvertTo-Nova128Petscii `
  35. (Get-Content -Raw -LiteralPath (Join-Path $project "tests\compiler\counter.n8"))))
  36. $badPet = Join-Path $root "bad.pet"
  37. [IO.File]::WriteAllBytes($badPet, (ConvertTo-Nova128Petscii `
  38. (Get-Content -Raw -LiteralPath (Join-Path $project "tests\grammar\rejected\miss_end.n8"))))
  39. New-Nova128Disk -Path $work -Files @(
  40. @{ Name = "n128c"; Path = $driver; Type = "prg" },
  41. @{ Name = "counter.n8"; Path = $counterPet; Type = "seq" },
  42. @{ Name = "bad.n8"; Path = $badPet; Type = "seq" })
  43. function Invoke-Compile {
  44. param([string]$Keys, [string]$Screenshot)
  45. if (Test-Path -LiteralPath $Screenshot) { Remove-Item -LiteralPath $Screenshot -Force }
  46. & (Join-Path $PSScriptRoot "launch-compiler.ps1") -CompilerPrg $driver -DiskImage $work `
  47. -SkipPrepare -Keys $Keys -KeyDelay 4000 -LimitCycles 200000000 `
  48. -Screenshot $Screenshot -Warp | Out-Host
  49. if (-not (Test-Path -LiteralPath $Screenshot)) {
  50. throw "the compiler session produced no exit screenshot"
  51. }
  52. }
  53. function Get-Listing {
  54. return ((& $c1541 -attach $work -list 2>&1) -join "`n")
  55. }
  56. function Read-DiskFile {
  57. param([string]$Name, [string]$Type, [string]$Dest)
  58. if (Test-Path -LiteralPath $Dest) { Remove-Item -LiteralPath $Dest -Force }
  59. & $c1541 $work -read "$Name,$Type" $Dest 2>&1 | Out-Null
  60. if (-not (Test-Path -LiteralPath $Dest)) { throw "could not read $Name,$Type from the disk" }
  61. return ,([IO.File]::ReadAllBytes($Dest))
  62. }
  63. function Get-ScreenText {
  64. param($Session)
  65. $ram = Read-Nova128Memory $Session 0x0400 1000
  66. $rows = for ($r = 0; $r -lt 25; $r++) {
  67. $chars = for ($c = 0; $c -lt 40; $c++) {
  68. $code = $ram[$r * 40 + $c]
  69. if ($code -le 0x1F) { [char]($code + 0x40) } elseif ($code -le 0x3F) { [char]$code } else { '?' }
  70. }
  71. -join $chars
  72. }
  73. return ($rows -join "`n")
  74. }
  75. # 1: the on-screen summary, read from a copy so the three launcher runs below
  76. # still start from an image without outputs.
  77. $summaryDisk = Join-Path $root "summary.d81"
  78. Copy-Item -LiteralPath $work -Destination $summaryDisk -Force
  79. $session = Start-Nova128X128 -Autostart $summaryDisk -Drive8Image $summaryDisk -Port $Port `
  80. -Keys "counter.n8\n" -KeyDelay 4000 -Screenshot (Join-Path $root "summary-screen.png")
  81. try {
  82. $screenText = ""
  83. $deadline = [DateTime]::UtcNow.AddSeconds(120)
  84. while ([DateTime]::UtcNow -lt $deadline) {
  85. Invoke-Nova128Monitor $session "x" | Out-Null
  86. Start-Sleep -Seconds 1
  87. $screenText = Get-ScreenText $session
  88. if ($screenText -match "OUTPUT COUNTER\.PRG" -and $screenText -match "0 ERRORS" -and
  89. $screenText -match "SOURCE COUNTER\.N8") { break }
  90. }
  91. } finally {
  92. Stop-Nova128X128 $session
  93. }
  94. foreach ($needle in @("NOVA128 COMPILER", "SOURCE COUNTER.N8", "OUTPUT COUNTER.PRG", "0 ERRORS")) {
  95. if ($screenText -notmatch [regex]::Escape($needle)) {
  96. $failures += "the summary did not show '$needle'"
  97. }
  98. }
  99. # 2: success through the launcher.
  100. Invoke-Compile -Keys "counter.n8\n" -Screenshot (Join-Path $root "counter-summary.png")
  101. $listing = Get-Listing
  102. if ($listing -notmatch '"counter\.prg"\s+prg') { $failures += "COUNTER.PRG is missing" }
  103. if ($listing -notmatch '"counter\.map"\s+seq') { $failures += "COUNTER.MAP is missing" }
  104. if ($listing -match '"counter\.err"') { $failures += "a clean source left COUNTER.ERR" }
  105. $prgPath = Join-Path $root "counter.prg"
  106. $prg = Read-DiskFile -Name "counter.prg" -Type "p" -Dest $prgPath
  107. $stub = [byte[]](0x0B, 0x1C, 0x0A, 0x00, 0x9E, 0x37, 0x31, 0x38, 0x31, 0x00, 0x00, 0x00)
  108. if ($prg.Length -lt 14 -or $prg[0] -ne 0x01 -or $prg[1] -ne 0x1C) {
  109. $failures += "COUNTER.PRG does not load at `$1C01"
  110. } else {
  111. for ($i = 0; $i -lt $stub.Length; $i++) {
  112. if ($prg[2 + $i] -ne $stub[$i]) {
  113. $failures += ("COUNTER.PRG stub byte {0} is {1:X2}, expected {2:X2}" -f $i, $prg[2 + $i], $stub[$i])
  114. break
  115. }
  116. }
  117. }
  118. # c1541 translates PETSCII CR to CRLF on read, so normalize before matching.
  119. $map = ([Text.Encoding]::ASCII.GetString((Read-DiskFile -Name "counter.map" -Type "s" `
  120. -Dest (Join-Path $root "counter.map"))) -replace "`r", "`n")
  121. $mapLines = $map -split "`n"
  122. $codeMatch = [regex]::Match($map, '(?im)^SECTION CODE ([0-9a-f]{4}) ([0-9a-f]{4})')
  123. $startMatch = [regex]::Match($map, '(?im)^SECTION START ([0-9a-f]{4}) ([0-9a-f]{4})')
  124. if ($mapLines[0] -ne "NOVA128 MAP 1") { $failures += "MAP header is '$($mapLines[0])'" }
  125. if ($map -notmatch '(?im)^ENTRY 1c0d') { $failures += "MAP ENTRY is not 1C0D" }
  126. if ($map -notmatch '(?im)^SECTION STUB 1c01 000c') { $failures += "MAP STUB section is wrong" }
  127. if (-not $startMatch.Success) {
  128. $failures += "MAP has no START section"
  129. } elseif ([Convert]::ToInt32($startMatch.Groups[1].Value, 16) -ne 0x1C0D) {
  130. $failures += "MAP START does not begin at 1C0D"
  131. }
  132. if (-not $codeMatch.Success) {
  133. $failures += "MAP has no CODE section"
  134. } else {
  135. $codeStart = [Convert]::ToInt32($codeMatch.Groups[1].Value, 16)
  136. $codeSize = [Convert]::ToInt32($codeMatch.Groups[2].Value, 16)
  137. if ($codeStart -ne 0x1C57) { $failures += ("CODE starts at {0:X4}, expected 1C57" -f $codeStart) }
  138. if ($prg.Length -ne (2 + 12 + 0x4A + $codeSize)) {
  139. $failures += ("PRG is {0} bytes, MAP accounts for {1}" -f $prg.Length, (2 + 12 + 0x4A + $codeSize))
  140. }
  141. if ($codeSize -eq 0) { $failures += "CODE section is empty" }
  142. }
  143. # 3: a syntax error writes the ERR file and no PRG, and leaves COUNTER.PRG alone.
  144. Invoke-Compile -Keys "bad.n8\n" -Screenshot (Join-Path $root "bad-summary.png")
  145. $listing = Get-Listing
  146. if ($listing -notmatch '"bad\.err"\s+seq') { $failures += "BAD.ERR is missing" }
  147. if ($listing -match '"bad\.prg"') { $failures += "a failing source produced BAD.PRG" }
  148. if ($listing -match '"bad\.map"') { $failures += "a failing source produced BAD.MAP" }
  149. $errText = [Text.Encoding]::ASCII.GetString((Read-DiskFile -Name "bad.err" -Type "s" `
  150. -Dest (Join-Path $root "bad.err")))
  151. if ($errText -notmatch '^E\d{3} BAD\.N8 \d+ ') { $failures += "BAD.ERR has no catalogued diagnostic" }
  152. if ($listing -notmatch '"counter\.prg"\s+prg') { $failures += "the failure removed COUNTER.PRG" }
  153. $afterFailure = Read-DiskFile -Name "counter.prg" -Type "p" -Dest (Join-Path $root "counter-after.prg")
  154. if ([Convert]::ToBase64String($afterFailure) -ne [Convert]::ToBase64String($prg)) {
  155. $failures += "the failing run changed COUNTER.PRG"
  156. }
  157. # 4: an existing output is refused and the file stays byte-identical.
  158. Invoke-Compile -Keys "counter.n8\n" -Screenshot (Join-Path $root "collision-summary.png")
  159. $listing = Get-Listing
  160. if (([regex]::Matches($listing, '"counter\.prg"')).Count -ne 1) {
  161. $failures += "the collision run changed the COUNTER.PRG directory entry"
  162. }
  163. $afterCollision = Read-DiskFile -Name "counter.prg" -Type "p" -Dest (Join-Path $root "counter-again.prg")
  164. if ([Convert]::ToBase64String($afterCollision) -ne [Convert]::ToBase64String($prg)) {
  165. $failures += "a refused output changed COUNTER.PRG"
  166. }
  167. # 5: the generated program itself runs and reaches its started/pass contract.
  168. $runSession = Start-Nova128X128 -Autostart $prgPath -Port ($Port + 1) `
  169. -Screenshot (Join-Path $root "counter-run.png")
  170. try {
  171. $mb = Wait-Nova128Mailbox $runSession -TimeoutSeconds 120
  172. } finally {
  173. Stop-Nova128X128 $runSession
  174. }
  175. if ($mb[0] -ne 0x4E -or $mb[1] -ne 0x38) { $failures += "the generated program did not initialise the mailbox" }
  176. if ($mb[2] -ne 0x03) { $failures += ("producer {0:X2}, expected 03 (generated program)" -f $mb[2]) }
  177. if ($mb[3] -ne 0xA5) { $failures += ("generated program status {0:X2}, expected A5" -f $mb[3]) }
  178. if ($failures) { throw ("n128c verification failed:`n " + ($failures -join "`n ")) }
  179. Write-Host ("summary: SOURCE COUNTER.N8 / OUTPUT COUNTER.PRG / 0 ERRORS")
  180. Write-Host ("success: COUNTER.PRG {0} bytes, COUNTER.MAP {1} bytes, no COUNTER.ERR" -f
  181. $prg.Length, $map.Length)
  182. Write-Host ("failure: BAD.ERR {0}, no BAD.PRG, COUNTER.PRG unchanged" -f $errText.Trim())
  183. Write-Host "injection: prepare-disk.ps1 wrote build/n128c.prg byte-identically as n128c"
  184. Write-Host "collision: OUTPUT EXISTS and COUNTER.PRG unchanged"
  185. Write-Host "run: generated COUNTER.PRG reported MB_ST_PASS in x128"

Powered by TurnKey Linux.