123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128 |
- #!/usr/bin/env python3
- template = """\
- @Loader:
- GOSUB {lbl[DefFn]}
- IF FN W({sym[HIMEM]})<{sym[LastByte]} THEN PRINT "Not enough memory":STOP
- CLEAR 9,{sym[Start]}:BLOAD"{filename}"
- PRINT "Ready, press F5 to run tests":KEY 5,"\x15run"+CHR$(13)
- @LastLoader:
- # The DELETE statement also stops the program, so we need the user to press F5
- DELETE {lbl[Loader]}-{lbl[LastLoader]}
- GOSUB {lbl[DefFn]}
- DEF USR={sym[Start]}
- S=0:SCREEN S:PRINT "Testing, please wait..."
- @NextMode:
- E=USR(0)
- GOSUB {lbl[PrintResults]}
- S=S+1:IF S < 4 THEN SCREEN S:GOTO {lbl[NextMode]}
- END
- @PrintResults:
- SCREEN 1
- COLOR 15,4-2*(E<>0),4
- PRINT "Screen mode:";S
- PRINT "Error code (0=no error):";E
- PRINT "Cycles/frame:";FN Z({sym[CycFrm1]})
- PRINT "ACK works ";FN S({sym[AckAfterInt]});"cyc. after INT"
- PRINT "Bit 7 set ";FN S({sym[Bit7AfterInt]});"cyc. after INT"
- PRINT "ACK takes";FN S({sym[AckBetween1]});"to";\
- FN S({sym[AckBetween2]});"cycles"
- PRINT "First fast wr. failure:";FN Z({sym[FirstBad1]})
- IF S<>3 THEN PRINT "Press a key for next mode...";INPUT$(1)
- RETURN
- @DefFn:
- DEFINT A-Y
- # Signed byte, note condition returns -1 if true
- DEF FN S(A)=PEEK(A)+256*(PEEK(A)>127)
- # Signed word
- DEF FN W(A)=PEEK(A)+256*FN S(A+1)
- DEF FN Z(A)=PEEK(A)+256*PEEK(A+1)+65536*PEEK(A+2)
- RETURN
- @1000:
- GOSUB {lbl[DefFn]}
- FOR N=&H3000 TO &H3FFF STEP 2:IF VPEEK(N)=252 AND VPEEK(N+1)=254 THEN NEXT
- PRINT HEX$(N-&H3000)
- FOR N=N TO &H3FFE:U=VPEEK(N)
- IF U<>252 AND U<>254 AND U<>1 THEN PRINT HEX$(N),HEX$(U)
- NEXT
- FOR N=&H3000 TO &H3FFE:PRINT HEX$(N),HEX$(VPEEK(N)):NEXT
- """
- fnames = {'cas':'CAS:VDPtst', 'dsk':'vdptest.bin'}
- import sys, re
- from asc2cld import tokenize, encode
- class Val(object):
- def __init__(self, n):
- self.u = n & 0xFFFF
- self.s = self.u if self.u < 32768 else self.u - 65536
- def __str__(self):
- return str(self.s) # return the signed one
- def main():
- if len(sys.argv) < 2 or sys.argv[1].lower() not in fnames:
- sys.stderr.write("Usage: python3 loadertpl.py {cas|dsk}\n")
- parsesym = re.compile(r'^([A-Za-z_?@.][A-Za-z0-9_?@.$]*)'
- r'\s+EQU\s+0([0-9A-F]{4})H$')
- kind = sys.argv[1].lower()
- sym = {}
- f = open('vdptest%s.sym' % kind[0], 'r')
- try:
- for line in f:
- g = parsesym.search(line)
- if g:
- r = Val(int(g.group(2), 16))
- assert g.group(0) not in sym
- sym[g.group(1)] = r
- finally:
- f.close()
- fname = fnames[kind]
- # Deal with the line breaks as inserted by Python in this .py source file
- prg = template.replace('\r\n','\n').replace('\r','\n').split('\n')
- # Parse labels and add line numbers
- labels = {}
- offset = 0
- for idx in range(len(prg)):
- while idx < len(prg):
- linenum = (idx + 1) * 10 + offset
- line = prg[idx].lstrip(' ')
- if line == '' or line.startswith('#'):
- del prg[idx]
- continue
- if line.startswith('@'):
- if not line.endswith(':'):
- raise Exception('Incorrect label syntax (missing colon after label)')
- label = line[1:-1]
- if label.isnumeric():
- offset = int(label, 0) - (idx + 1) * 10
- else:
- labels[label] = linenum
- del prg[idx]
- continue
- prg[idx] = str(linenum) + line
- break
- prg = '\r\n'.join(prg)
- prg = prg.format(sym=sym, filename=fname, lbl=labels)
- if kind == 'cas':
- prg = b'\xFF' + tokenize(prg)
- else:
- prg = encode(prg)
- sys.stdout.buffer.write(prg)
- main()
|