You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

106 line
4.3KB

  1. # E01-S05: link the memory-map skeleton against cfg/compiler.cfg.
  2. # build-map-skeleton.ps1 normal build, prints segment usage
  3. # build-map-skeleton.ps1 -Overflow ZP build that must fail in ld65
  4. [CmdletBinding()]
  5. param(
  6. [ValidateSet("", "ZP", "COMMON", "MAIN", "SWSTACK", "TABLES")]
  7. [string]$Overflow = ""
  8. )
  9. $ErrorActionPreference = "Stop"
  10. $project = Split-Path $PSScriptRoot -Parent
  11. $build = Join-Path $project "build"
  12. $config = Join-Path $project "cfg\compiler.cfg"
  13. $sources = @(
  14. (Join-Path $project "src\compiler\mmu.s"),
  15. (Join-Path $project "tests\platform\map-skeleton.s")
  16. )
  17. $suffix = if ($Overflow) { "-overflow-" + $Overflow.ToLowerInvariant() } else { "" }
  18. $stem = Join-Path $build ("map-skeleton" + $suffix)
  19. $program = "$stem.prg"
  20. $map = "$stem.map"
  21. $labels = "$stem.lbl"
  22. $ca65 = (Get-Command ca65 -ErrorAction Stop).Source
  23. $ld65 = (Get-Command ld65 -ErrorAction Stop).Source
  24. New-Item -ItemType Directory -Force -Path $build | Out-Null
  25. foreach ($path in @($program, $map, $labels)) {
  26. if (Test-Path -LiteralPath $path) { Remove-Item -LiteralPath $path -Force }
  27. }
  28. $objects = @()
  29. foreach ($source in $sources) {
  30. $object = Join-Path $build (([IO.Path]::GetFileNameWithoutExtension($source)) + $suffix + ".o")
  31. $defines = @()
  32. if ($Overflow) { $defines = @("-D", "OVERFLOW_$Overflow=1") }
  33. & $ca65 --cpu 6502 @defines -o $object $source
  34. if ($LASTEXITCODE -ne 0) { throw "ca65 failed on $source" }
  35. $objects += $object
  36. }
  37. $linkOutput = & $ld65 -C $config -o $program -m $map -Ln $labels @objects 2>&1
  38. $linkExit = $LASTEXITCODE
  39. if ($Overflow) {
  40. $text = ($linkOutput | Out-String)
  41. if ($linkExit -eq 0) { throw "OVERFLOW_$Overflow linked; capacity check failed to fire" }
  42. if ($text -notmatch "(?i)overflows memory area") {
  43. throw "OVERFLOW_$Overflow failed for an unexpected reason: $text"
  44. }
  45. $area = [regex]::Match($text, "(?i)overflows memory area\W+(\w+)").Groups[1].Value
  46. Write-Host ("overflow {0}: ld65 rejected it (memory area {1})" -f $Overflow, $area)
  47. return
  48. }
  49. if ($linkExit -ne 0) { throw ("ld65 failed:`n" + ($linkOutput | Out-String)) }
  50. # Segment usage from the map file: name, start, end, size.
  51. $segments = @{}
  52. $mapText = Get-Content -Raw -LiteralPath $map
  53. $block = [regex]::Match($mapText, "(?s)Segment list:.*?-{5,}\r?\n(.*?)\r?\n\r?\n").Groups[1].Value
  54. foreach ($line in ($block -split "\r?\n")) {
  55. $m = [regex]::Match($line, "^(\w+)\s+([0-9A-F]{6})\s+([0-9A-F]{6})\s+([0-9A-F]{6})")
  56. if ($m.Success) {
  57. $segments[$m.Groups[1].Value] = @{
  58. Start = [Convert]::ToInt32($m.Groups[2].Value, 16)
  59. End = [Convert]::ToInt32($m.Groups[3].Value, 16)
  60. Size = [Convert]::ToInt32($m.Groups[4].Value, 16)
  61. }
  62. }
  63. }
  64. # Contract checks that ld65 cannot express: fixed placements.
  65. function Require-Segment([string]$name, [int]$lo, [int]$hi) {
  66. if (-not $segments.ContainsKey($name)) { throw "segment $name missing from map" }
  67. $seg = $segments[$name]
  68. if ($seg.Size -gt 0 -and ($seg.Start -lt $lo -or $seg.End -gt $hi)) {
  69. throw ("segment {0} `${1:X4}-`${2:X4} outside `${3:X4}-`${4:X4}" -f
  70. $name, $seg.Start, $seg.End, $lo, $hi)
  71. }
  72. }
  73. Require-Segment "ZEROPAGE" 0x0002 0x00FF
  74. Require-Segment "COMMON" 0x1300 0x18FF
  75. Require-Segment "MAILBOX" 0x1BF0 0x1BFF
  76. Require-Segment "STARTUP" 0x1C0D 0xB7FF
  77. Require-Segment "CODE" 0x1C0D 0xB7FF
  78. if ($segments["STARTUP"].Start -ne 0x1C0D) { throw "STARTUP does not begin at `$1C0D" }
  79. $labelText = Get-Content -Raw -LiteralPath $labels
  80. if ($labelText -notmatch "(?im)^al\s+001C0D\s+\.skel_entry\s*$") {
  81. throw "skel_entry is not at `$1C0D (the SYS 7181 target)"
  82. }
  83. Require-Segment "SWSTACK" 0xB800 0xBFFF
  84. Require-Segment "TABLES" 0x6B00 0xBFFF
  85. if ($segments["MAILBOX"].Start -ne 0x1BF0) { throw "mailbox is not at `$1BF0" }
  86. $bytes = [IO.File]::ReadAllBytes($program)
  87. if ($bytes[0] -ne 0x01 -or $bytes[1] -ne 0x1C) { throw "load address is not `$1C01" }
  88. Write-Host ("built {0} ({1} bytes)" -f $program, $bytes.Length)
  89. $limits = [ordered]@{
  90. ZEROPAGE = 0x00FE; COMMON = 0x0600; SWSTACK = 0x0800; TABLES = 0x5500
  91. }
  92. foreach ($name in ($segments.Keys | Sort-Object { $segments[$_].Start })) {
  93. $seg = $segments[$name]
  94. $limit = if ($limits.Contains($name)) { " of {0}" -f $limits[$name] } else { "" }
  95. Write-Host (" {0,-9} `${1:X4}-`${2:X4} {3,6} bytes{4}" -f
  96. $name, $seg.Start, $seg.End, $seg.Size, $limit)
  97. }

Powered by TurnKey Linux.