loadertpl.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  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:SCREEN S:PRINT "Testing, please wait..."
  14. @NextMode:
  15. E=USR(0)
  16. GOSUB {lbl[PrintResults]}
  17. S=S+1:IF S < 4 THEN SCREEN S:GOTO {lbl[NextMode]}
  18. END
  19. @PrintResults:
  20. SCREEN 1
  21. COLOR 15,4-2*(E<>0),4
  22. PRINT "Screen mode:";S
  23. PRINT "Error code (0=no error):";E
  24. PRINT "Cycles/frame:";FN Z({sym[CycFrm1]})
  25. PRINT "ACK works ";FN S({sym[AckAfterInt]});"cyc. after INT"
  26. PRINT "Bit 7 set ";FN S({sym[Bit7AfterInt]});"cyc. after INT"
  27. PRINT "ACK takes";FN S({sym[AckBetween1]});"to";\
  28. FN S({sym[AckBetween2]});"cycles"
  29. PRINT "First fast wr. failure:";FN Z({sym[FirstBad1]})
  30. IF S<>3 THEN PRINT "Press a key for next mode...";INPUT$(1)
  31. RETURN
  32. @DefFn:
  33. DEFINT A-Y
  34. # Signed byte, note condition returns -1 if true
  35. DEF FN S(A)=PEEK(A)+256*(PEEK(A)>127)
  36. # Signed word
  37. DEF FN W(A)=PEEK(A)+256*FN S(A+1)
  38. DEF FN Z(A)=PEEK(A)+256*PEEK(A+1)+65536*PEEK(A+2)
  39. RETURN
  40. @1000:
  41. GOSUB {lbl[DefFn]}
  42. FOR N=&H3000 TO &H3FFF STEP 2:IF VPEEK(N)=252 AND VPEEK(N+1)=254 THEN NEXT
  43. PRINT HEX$(N-&H3000)
  44. FOR N=N TO &H3FFE:U=VPEEK(N)
  45. IF U<>252 AND U<>254 AND U<>1 THEN PRINT HEX$(N),HEX$(U)
  46. NEXT
  47. FOR N=&H3000 TO &H3FFE:PRINT HEX$(N),HEX$(VPEEK(N)):NEXT
  48. """
  49. fnames = {'cas':'CAS:VDPtst', 'dsk':'vdptest.bin'}
  50. import sys, re
  51. from asc2cld import tokenize, encode
  52. class Val(object):
  53. def __init__(self, n):
  54. self.u = n & 0xFFFF
  55. self.s = self.u if self.u < 32768 else self.u - 65536
  56. def __str__(self):
  57. return str(self.s) # return the signed one
  58. def main():
  59. if len(sys.argv) < 2 or sys.argv[1].lower() not in fnames:
  60. sys.stderr.write("Usage: python3 loadertpl.py {cas|dsk}\n")
  61. parsesym = re.compile(r'^([A-Za-z_?@.][A-Za-z0-9_?@.$]*)'
  62. r'\s+EQU\s+0([0-9A-F]{4})H$')
  63. kind = sys.argv[1].lower()
  64. sym = {}
  65. f = open('vdptest%s.sym' % kind[0], 'r')
  66. try:
  67. for line in f:
  68. g = parsesym.search(line)
  69. if g:
  70. r = Val(int(g.group(2), 16))
  71. assert g.group(0) not in sym
  72. sym[g.group(1)] = r
  73. finally:
  74. f.close()
  75. fname = fnames[kind]
  76. # Deal with the line breaks as inserted by Python in this .py source file
  77. prg = template.replace('\r\n','\n').replace('\r','\n').split('\n')
  78. # Parse labels and add line numbers
  79. labels = {}
  80. offset = 0
  81. for idx in range(len(prg)):
  82. while idx < len(prg):
  83. linenum = (idx + 1) * 10 + offset
  84. line = prg[idx].lstrip(' ')
  85. if line == '' or line.startswith('#'):
  86. del prg[idx]
  87. continue
  88. if line.startswith('@'):
  89. if not line.endswith(':'):
  90. raise Exception('Incorrect label syntax (missing colon after label)')
  91. label = line[1:-1]
  92. if label.isnumeric():
  93. offset = int(label, 0) - (idx + 1) * 10
  94. else:
  95. labels[label] = linenum
  96. del prg[idx]
  97. continue
  98. prg[idx] = str(linenum) + line
  99. break
  100. prg = '\r\n'.join(prg)
  101. prg = prg.format(sym=sym, filename=fname, lbl=labels)
  102. if kind == 'cas':
  103. prg = b'\xFF' + tokenize(prg)
  104. else:
  105. prg = encode(prg)
  106. sys.stdout.buffer.write(prg)
  107. main()