Because it requires desoldering to do so, OPK is the standard image format, and there's not really any need to.
What problem are you looking to solve?
Because it requires desoldering to do so, OPK is the standard image format, and there's not really any need to.
When I first asked the question I incorrectly assumed the ROM was socketed and easily removed for reading.
Code: Select all
SENDPACK:
LOCAL MC1$(72),MC2$(140),A$(255),A%(3)
LOCAL N%,M%,P%,L1%,L2%,C%,A
CLS
PRINT "Loading...";
REM MC1 is sizing, MC2 is pack read
REM CONV$:() converts hex codes to bytes in a string
MC1$=CONV$:("18EC00FF22804F3F62253A5FCE000A3F6025323F5F188C0280270C082711185D27F15A164F20023F5F3F63251820E43F5C1883000218C2003CFE22806F02E7033233ED045F4F1839")
MC2$=CONV$:("18EC04FD2284EC02FD2282EC00FD2280FF227EF622824F3F622527FE2284F622833F60251DFE2280E60008374F3F5E251033FE227E4FE304ED0424026C035F2001324F1839")
N%=ADDR(MC2$)+1 :REM +1 because first byte of string is length
M%=ADDR(A%()) :REM pointer to A%(), will load into 2 byte D register
DO
DO
CLS
PRINT "Pack? (B,C,D)";
P%=ASC(UPPER$(GET$))
IF P%=1
RETURN
ENDIF
UNTIL P%>=%B AND P%<=%D :REM %B gives ASCII value of 'B'
CLS
P%=P%-%A :REM make P% a num from 2 to 4 B: is 2, C: is 3
A%(1)=P%
C%=USR(ADDR(MC1$)+1,M%) :REM call MC1 sizing, with D as pointer to A%. A%(1) = pack no., returns X register value to C%
UNTIL C%<>246 : REM 246??
IF C%
RAISE C% :REM C% is error num
ENDIF
ONERR E:: :REM error handling, see label E:: at end of code
XFOPEN:("PACK.OPK",1,0) :REM open file on remote computer via serial
A$="OPK"+CHR$(A%(2))+CHR$(PEEKB(ADDR(A%())+4))+CHR$(A%(3) AND 255) :REM write OPK header, with size in A%(2) -high high, A%(0)+4 -> A%(3)-high, A%(3) AND 255 -> A%(3)-low, byte order is high-low
XFPUT:(A$) :REM write to OPK via serial
A$=REPT$(" ",255) :REM page buffer
A=65536.*A%(2)+A%(3) :REM A is pack size, A%(2)-topByte, + add A%(3) - pack size is 24 bit - topByte is top 8 bits
IF A%(3)<0
A=A+65536
ENDIF
L1%=INT(A/255) :REM L1% = no. of full pages in A
L2%=A-255.*L1% :REM L2% = length of last partial page
IF L2%<=253 :REM add 2 bytes to L2% if fit on page - to read 2x 0xFF bytes at end of pack, beyond size
L2%=L2%+2
ELSE
L2%=L2%-253 :REM if L2% is 254, subtract 253 (so L2% = 1)
L1%=L1%+1 :REM add one page to length, with one byte in it ( i.e. add 2 bytes)
ENDIF
A%(1)=ADDR(A$) :REM A$() buffer address, points to length byte followed by string
A%(2)=P%*256+0 :REM pack no. in high byte of A%(2)
A%(3)=0 :REM will be used to count pack address during read (with topByte byte in A%(2) low byte)
WHILE L1% :REM loop whilst page_count > 0, keeps reading pages and reducing page count
C%=USR(N%,M%) :REM call MC2 with D as addr of A%() (N%-addr of code, M%-addr of A%), read page or partial page, returns X register value to C%
IF C%=0
XFPUT:(A$) :REM if no errors, write A$ to serial
ELSE
RAISE C% :REM else, raise error
ENDIF
AT 1,1
PRINT L1%, :REM print no. of pages remaining
L1%=L1%-1 :REM reduce page count
ENDWH
A$=REPT$(" ",L2%) :REM A$ buffer for partial page
C%=USR(N%,M%) :REM read partial page with D as addr of A% (N%-addr of code, M%-addr of A%()), returns X register value to C%
IF C%=0
XFPUT:(A$) :REM if no errors, write A$ to serial
ELSEIF C%
RAISE C% :REM else, raise error
ENDIF
XFCLOSE: :REM close serial port
CLS
PRINT "Done";
PAUSE -20
RETURN
E::
ONERR OFF
C%=ERR
XFCLOSE:
RAISE C%
//
// RAM
// RAM:0000-RAM:008c
//
// sendpack machine code disassembled
// A is high byte of D, B is low byte of D
**************************************************************
* MC1 *
* pack sizing *
short record - length, type (type FF is invalid length)
long record - 02 80 highbyte lowbyte (of length)
**************************************************************
0000 18 XGDX // exchange D and X (move call value D - addr of A%() into X)
0001 ec 00 LDD 0x0,X // load D with value in X+0 (slot no.)
0003 ff 22 80 STX DAT_2280 // store X in 2280 (store addr of A%() within run time data store)
0006 4f CLRA // clear A
0007 3f 62 OS PK$SETP=>SUB_fffa // setpack slot to value in B (0-3 A: to D:, A: is internal memory storage)
0009 25 3a BCS LAB_0045 // if error, exit
000b 5f CLRB // clear B
000c ce 00 0a LDX #0xa // load X with 000A - skip header to 1st data record
000f 3f 60 OS PK$SADD=>SUB_fffa // set pack addr B-topByte, X-lowest 2 bytes
0011 25 32 BCS LAB_0045 // if error, exit
LAB_0013 XREF[2]: 0020(j), 002d(j) // LAB_0013 - start of main loop
0013 3f 5f OS PK$RWRD=>SUB_fffa // read a word from pack (2 bytes) to D
0015 18 XGDX // exchange D and X (D -> X)
0016 8c 02 80 CMPX #0x280 // compare X to 0280 - long record?
0019 27 0c BEQ LAB_0027 // branch if zero set (long record) to LAB__0027 - found long record
001b 08 INX // increase X
001c 27 11 BEQ LAB_002f // branch if zero set (word was FFFF) to LAB_002f - found end of pack
001e 18 XGDX // exchange D and X (X -> D)
001f 5d TSTB // test B for zero (low byte zero? word was xxFF?) found one FF byte - invalid short record length
0020 27 f1 BEQ LAB_0013 // branch if zero set (low byte FF) to LAB_0013 - back to main loop
0022 5a DECB // decrease B (?? B gets over written - clear zero flag?)
0023 16 TAB // transfer (copy) A to B (high byte to low byte)
0024 4f CLRA // clear A (low byte only for short record length)
0025 20 02 BRA LAB_0029 // branch to LAB_0029 (jump over read long record length)
LAB_0027 XREF[1]: 0019(j) // LAB_0027 - long record
0027 3f 5f OS PK$RWRD=>SUB_fffa // read a word from pack to D - length of record
LAB_0029 XREF[1]: 0025(j) // LAB_0029
0029 3f 63 OS PK$SKIP=>SUB_fffa // skip D bytes forward - skip record length
002b 25 18 BCS LAB_0045 // branch if carry set to LAB_0045 - error & exit
002d 20 e4 BRA LAB_0013 // branch to LAB_0013 + back to main loop
LAB_002f XREF[1]: 001c(j) // LAB_002f - found end of pack
002f 3f 5c OS PK$QADD=>SUB_fffa // read pack address to B-high X-low
0031 18 XGDX // exchange D and X (X to D, D to X)
0032 83 00 02 SUBD #0x2 // subtract 2 from low byte of addr (pack address before FFFF)
0035 18 XGDX // exchange D and X (D to X, X to D, B now has high byte of addr)
0036 c2 00 SBCB #0x0 // subtract 0 and carry from B (if carry, from subtracting 2, reduce high byte, B stays in D)
0038 3c PSHX // push X to stack (low byte of end addr to stack)
0039 fe 22 80 LDX DAT_2280 // load X from 2280 - addr of A%()
003c 6f 02 CLR 0x2,X // clear value in X+2
003e e7 03 STB 0x3,X // store B at X+3 (topByte byte of end of pack) at A%(2)-low
0040 32 PULA // pull A from stack (high byte of D)
0041 33 PULB // pull B from stack (low byte of D, low byte of addr)
0042 ed 04 STD 0x4,X // store D at X+4, store in A%(3) - high,low
0044 5f CLRB // clear B
LAB_0045 XREF[3]: 0009(j), 0011(j), 002b(j) // LAB_0045 - error & exit
0045 4f CLRA // clear A
0046 18 XGDX // exchange D and X - X is returned by USR (0 if ok)
0047 39 RTS // return
**************************************************************
* MC2 *
* pack read 1 page at a time * B -low of D, A -high of word register D
**************************************************************
sets pack address on each call - maybe pack address gets lost when data sent via serial over pack datalines?
can't guarantee pack address is preserved when control passes back to OPL and serial is used?
0048 18 XGDX // exchange D and X (move call value D - addr of A%() into X) X reg also a word
0049 ec 04 LDD 0x4,X // Load D with value in addr X+4 (& X+5) A%(3) - storage of pack address: high,low
004b fd 22 84 STD DAT_2284 // store D in 2284 - pack address (starts at zero), byte order: high, low
004e ec 02 LDD 0x2,X // load D with value in addr X+2 (& X+3) A%(2) - pack slot in high byte (X+2) 2282, X+3 topByte of address
0050 fd 22 82 STD DAT_2282 // store D in 2282 - pack slot no., 2283 is topByte
0053 ec 00 LDD 0x0,X // load D with value in addr X (& X+1) A%(1) - address of data buffer A$() (255 bytes or final partial page)
0055 fd 22 80 STD DAT_2280 // store D in 2280 - pointer to A$() buffer
0058 ff 22 7e STX DAT_227e // store X in 227E (& 227F) - pointer to A%()
005b f6 22 82 LDB DAT_2282 // load B from 2282 (load value in X+2) - pack no. to B (low byte of D)
005e 4f CLRA // clear A (high byte of D)
005f 3f 62 OS PK$SETP=>SUB_fffa // set pack slot to value in D (set to value from X+2, A%(2)-high)
0061 25 27 BCS LAB_008a // branch is carry set to LAB_008A - if error, exit
0063 fe 22 84 LDX DAT_2284 // load X from 2284 (load word from addr X+4) - restore X - pack address: high,low
0066 f6 22 83 LDB DAT_2283 // load B from 2283 (load high byte of value in addr X+3) - topByte
0069 3f 60 OS PK$SADD=>SUB_fffa // set pack address to value in B and X, set pack addr B-topByte, X-high,low of pack addr
006b 25 1d BCS LAB_008a // branch if carry set to LAB__008A - if error, exit
006d fe 22 80 LDX DAT_2280 // load X from 2280 (load X with value in 2280) load A$() pointer
0070 e6 00 LDB 0x0,X // load B with value in addr X (get value from A$() pointer address) - A$(0) is buffer length: 255 or less
0072 08 INX // increase X by 1, A$() pointer +1, move past length byte
0073 37 PSHB // push B to stack -value in A$(0) to stack
0074 4f CLRA // clear A (clear high byte of D) D is A,B: high,low
0075 3f 5e OS PK$READ=>SUB_fffa // read D pack bytes to address beginning at X, fill A$ from 2nd element (255 or less)
0077 25 10 BCS LAB_0089 // branch if carry set to LAB_0089, if error, pull A from stack, exit
0079 33 PULB // pull B from stack get A$(0) length value back from stack, D will now have buffer length
007a fe 22 7e LDX DAT_227e // load X from 227E - restore A%() pointer
007d 4f CLRA // clear A - clear high byte of D
007e e3 04 ADDD 0x4,X // add value in addr X+4 to D - add D to pack address
0080 ed 04 STD 0x4,X // store D in addr X+4 - store pack address
0082 24 02 BCC LAB_0086 // branch if carry clear to LAB_0086 - if no address overflow error - clear B & exit
0084 6c 03 INC 0x3,X // increase value in addr X+3 by 1 (otherwise increase topByte of pack address & exit)
LAB_0086 XREF[1]: 0082(j) // LAB_0086 - clear B & exit
0086 5f CLRB // clear B
0087 20 01 BRA LAB_008a // branch to LAB_008A
LAB_0089 XREF[1]: 0077(j) // LAB_0089 - pull A & exit
0089 32 PULA // pull A from stack
LAB_008a XREF[3]: 0061(j), 006b(j), 0087(j) // LAB_008A - error & exit
008a 4f CLRA // clear A
008b 18 XGDX // exchange D and X
008c 39 RTS // return