loadertpl.py 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138
  1. #!/usr/bin/env python3
  2. template = """\
  3. @Loader:
  4. GOSUB {lbl[DefFn]}
  5. IF FN W({sym[HIMEM]})<{sym[LastByte]} THEN PRINT "Not enough memory":STOP
  6. CLEAR 9,{sym[Start]}:BLOAD"{filename}"
  7. PRINT "Ready, press F5 to run tests":KEY 5,"\x15run"+CHR$(13)
  8. @LastLoader:
  9. # The DELETE statement also stops the program, so we need the user to press F5
  10. DELETE {lbl[Loader]}-{lbl[LastLoader]}
  11. GOSUB {lbl[DefFn]}
  12. DEF USR={sym[Start]}
  13. S=0
  14. @NextMode:
  15. SCREEN S:PRINT "Testing, please wait..."
  16. # Make all sprites visible
  17. FOR N=0 TO &H3E STEP 2:VPOKE N+N+&H1B00,N+8:VPOKE N+N+&H1B01,N*4:NEXT
  18. # Move sprite pattern table to 3000h, so we have at least some feedback
  19. VDP(6)=6
  20. E=USR(0)
  21. GOSUB {lbl[PrintResults]}
  22. S=S+1:IF S < 4 THEN {lbl[NextMode]}
  23. END
  24. @PrintResults:
  25. SCREEN 1:WIDTH 32
  26. COLOR 15,4-2*(E<>0),4
  27. PRINT "Screen mode:";S
  28. PRINT "Error code (0=no error):";E
  29. PRINT "Cycles/frame:";FN Z({sym[CycFrm1]})
  30. PRINT "ACK works ";FN S({sym[AckAfterInt]});"cyc. after INT"
  31. PRINT "Bit 7 set ";FN S({sym[Bit7AfterInt]});"cyc. after INT"
  32. PRINT "ACK takes";FN S({sym[AckBetween1]});"to";\
  33. FN S({sym[AckBetween2]});"cycles"
  34. PRINT "1st fast wr. failure cycles:"
  35. PRINT "12T:";FN Z({sym[FirstBad12]});" 14T:";FN Z({sym[FirstBad14]})
  36. PRINT "17T:";FN Z({sym[FirstBad17]});" 18T:";FN Z({sym[FirstBad18]})
  37. PRINT "19T:";FN Z({sym[FirstBad19]});" 20T:";FN Z({sym[FirstBad20]})
  38. PRINT "21T:";FN Z({sym[FirstBad21]});" 22T:";FN Z({sym[FirstBad22]})
  39. PRINT "23T:";FN Z({sym[FirstBad23]});" 24T:";FN Z({sym[FirstBad24]})
  40. IF S<>3 THEN PRINT "Press a key for next mode...";INPUT$(1)
  41. RETURN
  42. @DefFn:
  43. DEFINT A-Y
  44. # Signed byte, note condition returns -1 if true
  45. DEF FN S(A)=PEEK(A)+256*(PEEK(A)>127)
  46. # Signed word
  47. DEF FN W(A)=PEEK(A)+256*FN S(A+1)
  48. DEF FN Z(A)=PEEK(A)+256*PEEK(A+1)+65536*PEEK(A+2)
  49. RETURN
  50. @1000:
  51. GOSUB {lbl[DefFn]}
  52. FOR N=&H3000 TO &H3FFF STEP 2:IF VPEEK(N)=252 AND VPEEK(N+1)=254 THEN NEXT
  53. PRINT HEX$(N-&H3000)
  54. FOR N=N TO &H3FFE:U=VPEEK(N)
  55. IF U<>252 AND U<>254 AND U<>1 THEN PRINT HEX$(N),HEX$(U)
  56. NEXT
  57. FOR N=&H3000 TO &H3FFE:PRINT HEX$(N),HEX$(VPEEK(N)):NEXT
  58. """
  59. fnames = {'cas':'CAS:VDPtst', 'dsk':'vdptest.bin'}
  60. import sys, re
  61. from asc2cld import tokenize, encode
  62. class Val(object):
  63. def __init__(self, n):
  64. self.u = n & 0xFFFF
  65. self.s = self.u if self.u < 32768 else self.u - 65536
  66. def __str__(self):
  67. return str(self.s) # return the signed one
  68. def main():
  69. if len(sys.argv) < 2 or sys.argv[1].lower() not in fnames:
  70. sys.stderr.write("Usage: python3 loadertpl.py {cas|dsk}\n")
  71. parsesym = re.compile(r'^([A-Za-z_?@.][A-Za-z0-9_?@.$]*)'
  72. r'\s+EQU\s+0([0-9A-F]{4})H$')
  73. kind = sys.argv[1].lower()
  74. sym = {}
  75. f = open('vdptest%s.sym' % kind[0], 'r')
  76. try:
  77. for line in f:
  78. g = parsesym.search(line)
  79. if g:
  80. r = Val(int(g.group(2), 16))
  81. assert g.group(0) not in sym
  82. sym[g.group(1)] = r
  83. finally:
  84. f.close()
  85. fname = fnames[kind]
  86. # Deal with the line breaks as inserted by Python in this .py source file
  87. prg = template.replace('\r\n','\n').replace('\r','\n').split('\n')
  88. # Parse labels and add line numbers
  89. labels = {}
  90. offset = 0
  91. for idx in range(len(prg)):
  92. while idx < len(prg):
  93. linenum = (idx + 1) * 10 + offset
  94. line = prg[idx].lstrip(' ')
  95. if line == '' or line.startswith('#'):
  96. del prg[idx]
  97. continue
  98. if line.startswith('@'):
  99. if not line.endswith(':'):
  100. raise Exception('Incorrect label syntax (missing colon after label)')
  101. label = line[1:-1]
  102. if label.isnumeric():
  103. offset = int(label, 0) - (idx + 1) * 10
  104. else:
  105. labels[label] = linenum
  106. del prg[idx]
  107. continue
  108. prg[idx] = str(linenum) + line
  109. break
  110. prg = '\r\n'.join(prg)
  111. prg = prg.format(sym=sym, filename=fname, lbl=labels)
  112. if kind == 'cas':
  113. prg = b'\xFF' + tokenize(prg)
  114. else:
  115. prg = encode(prg)
  116. sys.stdout.buffer.write(prg)
  117. main()