1
0
mirror of https://github.com/PDP-10/its.git synced 2026-01-17 00:33:22 +00:00
PDP-10.its/src/sysen3/hexify.1
Eric Swenson cc5789597e Added HEXIFY.
Resolves #314.

Source from AR3: SRA; HEXIFY 1.
2016-12-21 10:40:04 +01:00

579 lines
13 KiB
Groff
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;-*- Midas -*-
;Hex format:
;:LL AAAA TT DD DD DD DD .. DD CC
;LL: number of DD bytes AAAA: load address TT: 00 (or 01 for end rec)
;DD: data bytes. CC: complemented checksum of all the bytes
;Last record has rec-len 0, or can use TT=01 thing with AAAA=execution address
;For CP/M execution address is irrelevant. (always 0100)
A=1 ;general purpose, arg passing
B=2
C=3
D=4
RLen=5 ;intended record length
RRLen=6 ;real record length (after ignoring gapchrs)
Chksum=7 ;checksum while record-building
Cnt=10 ;number of bytes left in file
BP=11 ;ildb byte point to file buffer
TT=12 ;super temps, clobberable by all routines/macros
TT1=13
p=17
dskf==1 ;disk channel
ttyo==2 ;tty output channel, for typeout.
Call=PUSHJ P,
Return=POPJ P,
PDLen==20
JCLen==20 ;100 chars, more than enuff
;;offsets in filename blocks
DEV==0
FN1==1
FN2==2
SNM==3
define syscal op,args
.CALL [SETZ ? SIXBIT /op/ ? args ((SETZ))]
termin
define Type &string
movei TT,<.Length string>
move TT1,[440700,,[Ascii string]]
.call TTYTYP
.Lose %LsSys
Termin
define Terpri chnl
.iot chnl,CR
.iot chnl,LF
Termin
;;options variables
RecSep: 1 ;0: nothing separates record
;1: CRLF after each record
;other choices as need arises.
gapchr: -1 ;if ge 0, character which we assume gets placed
;in gaps. Will make hex file which may have
;gaps instead of writing out this character, if
;that will save some room in the file.
;if -1, write out all chars, no gaps allowed.
Addr: 400 ;100H - initial load addr, updated as we go
EAddr: -1 ;execution address (defaultly same as Addr)
EType: 1 ;type of last, 0-length record - 0 or 1
RecLen: 16. ;maximum record length
Switch: ;;A has character
cain A,"C ;/C - contiguous records
jrst SwiC
cain A,"G
jrst SwiG ;/G - gaps allowed
cain A,"A
jrst SwiA ;/A - load address
cain A,"E
jrst SwiE ;/E - execution address
cain A,"T
jrst SwiT ;/T - type of last record
cain A,"R
jrst SwiR ;/R - record length
Type "AUnknown switch /"
.iot ttyo,A
Type " ignored.
"
Ret1: aos (p) ;don't re-use char
Ret: return
SwiC: setzm RecSep
jrst Ret1
SwiG: ;;Gaps allowed. /G:hh where hh are hex digits.
setzm GapChr ;default gap char is 0
ildb A,BP
caie A,":
return
call UnHex
cain A,"H
aos (p) ;don't reuse char if luser typed "H" at end
movem TT,GapChr ;if GapChr out of range, no big deal...
return
SwiA: ;;/A:hhhh - load address
ildb A,BP
caie A,":
return
call UnHex
cain A,"H
aos (p)
movem TT,Addr
return
SwiE: ;;/E:hhhh - execution address
ildb A,BP
caie A,":
return
call UnHex
cain A,"H
aos (p)
movem TT,EAddr
return
SwiT: ;;/T - type of last record is 00
setzm EType
jrst ret1
SwiR: ;;/R:hh - record length
ildb A,BP
caie A,":
return
call UnHex
cain A,"H
aos (p)
andi TT,377
jumpe TT,[Type "ARecord length must be between 1 and FF
"
return]
movem TT,RecLen
return
UnHex: ;;Read Hex until get non-hex (leave in A). TT gets value
setz TT,
UnHex1: ildb A,BP
cail A,140
subi A,40
cail A,"0
caile A,"F
return
caile A,"9
cail A,"A
skipa
return
subi A,"0
cail A,10.
addi A,"0-"A+10.
imuli TT,16.
add TT,A
jrst UnHex1
Begin: Move P,PDList
Syscal OPEN,[%Clbit,,.uao\%TJDIS ;Allow ^P usage
%Climm,,TTYo
[Sixbit /TTY/]]
.Lose %LsFil
call Jcl ;parse jcl
skipge EAddr
jrst [move TT,Addr ? movem TT,EAddr ? jrst .+1]
skipn ISNAME
.suset [.rHSname,,ISNAME]
skipn IFN1
.suset [.rUNAME,,IFN1]
call RdFile ;snarf file, set up BP,Cnt
Type "AHexifying file "
movei A,IDEV ? Call FilTyp
Terpri ttyo
skipn OSNAME
.suset [.rHSname,,OSNAME]
skipn OFN1
jrst [move TT,IFN1 ? movem TT,OFN1 ? jrst .+1]
call OutOpn ;open output file
Type "ALoad Address="
move A,Addr ? Call H2Typ
Type "H, Execution Address="
move A,EAddr ? Call H2Typ ?
Type "HARecord Length="
move A,RecLen ? Call H1Typ
skipge A,GapChr
jrst [Type "H, no gaps"
jrst B1]
jumpe A,[Type "H, gaps allowed"
jrst B1]
Type "H, gap char="
call H1Typ
B1: type ".
"
call Hex ;Do it (closes file)
.close dskf,
move A,RecNum ? Call HTyp
type "H records written to "
movei A,ODEV ? call FilTyp
Die: .logout 1,
Help: Type "A:HEXIFY input file,output file /switch /switch /switch
Convert input file, which must be a 'COM' file, into Intel Hex format.
Input file defaults to DSK:hsname;uname COM,
output file defaults to DSK:hsname;input_fn1 HEX.
Normally creates records of length 10H, each followed by CRLF, starting
with load address of 0100H. The last record has length 0, and is of type
01, with address same as the initial load address. Switches can be used
to change this.
In the switch descriptions, 'h' stands for hex digits.
/C -- make records Contiguous, i.e. do not put CRLF after each one.
/A:hhhh -- Make the initial load address hhhh
/E:hhhh -- Make the execution address (the address on last record) be hhhh
/T -- make the last record be of type 00
/G -- allow 'gaps'. The program will try to save space by not writing out
all the 0 bytes, manipulating the address field of records instead.
/G:hh -- like /G, but do it for 'hh' bytes, rather than 00. This is if your
loader fills gaps with something other than 0's (Huh?)
/R:hh -- make each record (at most) hh bytes long.
"
jrst Die
Jcl: ;;BP=pointer to jcl, D=first filename block.
;;clobbers everything in sight
.break 12,[..rJCL,,JCLBUF]
skipn JCLBUF
jrst Help ;No jcl -> help
move BP,[440700,,JCLBUF]
JclQp: ;;check for first char being ?
ildb A,BP
caie A,40
cain A,^I
jrst JclQp
cain A,"?
jrst Help
movei D,IDEV
jrst JclReU
JclNew: seto A, ;don't re-use last char
JclReU: movei Cnt,6
setz C,
move B,[440600,,C]
skipge A
JclNxt: ildb A,BP
jumpe A,JclFil
caie A,^C
cain A,^M
jrst JclFil
skipe Quote
jrst [setzm Quote ? jrst JclAdd] ;if quoting, ok
cain A,^Q
jrst [setom Quote ? jrst JclNxt]
cain A,":
jrst [skipe C ? movem C,DEV(D)
jrst JclNew]
cain A,";
jrst [skipe C ? movem C,SNM(D)
jrst JclNew]
caie A,",
cain A,"/
jrst JclFil
caie A,40
cain A,^I
jrst JclFil
JclAdd: sojl Cnt,JclNxt ;ignore extra chars if passed limit
cail A,140
subi A,40
subi A,40
idpb A,B
jrst JclNxt
JclFil: ;A has ^@,^C,^M,comma,/,space,tab
jumpe C,JclF1
skipn FN1(D)
jrst [movem C,FN1(D) ? jrst JclF1]
movem C,FN2(D)
JclF1: caie A,40
cain A,^I
jrst JclNew
cain A,",
jrst [movei D,ODEV ? jrst JclNew]
caie A,"/
return ;all but Space,tab,slash and comma say DONE!
;;Ok, have a switch
JclSwi: ildb A,BP
cail A,140
subi A,40
call Switch ;skip return if don't want to reuse A
jrst JclReU
jrst JclNew
;;FilTyp(A=file block)
FilTyp: move TT,DEV(A)
call 6Type ;print device
.iot ttyo,[":]
.iot ttyo,Space
move TT,SNM(A)
call 6Type
.iot ttyo,[";]
.iot ttyo,Space
move TT,FN1(A)
call 6Type
.iot ttyo,Space
move TT,FN2(A)
6Type: setz TT1,
rotc TT,6
addi TT1,40
.iot ttyo,TT1
jumpn TT,6TYPE
return
Hexout: ;;A has byte to add to Record buffer
move TT,A
lsh TT,-4
call Hexou1
move TT,A
Hexou1: call HToA
idpb TT,RecBP
return
HTyp: ;;A has number- type it out in full.
move TT,A
jffo TT,.+3
.iot ttyo,["0]
return
andi TT1,74 ;TT1= 4*(number of leading zero digits)
subi TT1,40
HTyp1: lsh TT,(TT1)
call HToA
.iot ttyo,TT
move TT,A
addi TT1,4
jumple TT1,HTyp1
return
H2Typ: ;;A has word
push p,A
lsh A,-8.
call H1Typ
pop p,A
H1Typ: ;;A has byte
move TT,A
lsh TT,-4
call H1Typ1
move TT,A
H1Typ1: call HToA
.iot ttyo,TT
return
HToA: andi TT,17
addi TT,"0
caile TT,"9
addi TT,-10.+"A-"0
return
WrRec: ;;RRLen has length of record (number of data bytes) - clobbered
;;write stored record to disk file, reset record bp.
add RRLen,RRLen
addi RRLen,11. ;A:total length,in chars, of output record
move TT,[440700,,Record]
syscall SIOT,[%Climm,,dskf ? TT ? RRLen] ;output it
.Lose %LsFil
aos RecNum ;for record keeping
move TT,[350700,,Record]
movem TT,RecBP ;reset byte pointer
skipg RecSep
return
terpri dskf
return
Hex: ;;ADDR / RecLen set up
;;File snarfed, Cnt,BP set up. Assume Cnt greater'n 0
ildb A,BP
came A,gapchr
jrst Hex1
aos Addr
sojle Cnt,Done
jrst Hex
Hex1: ;gapchrs skipped. A has first byte, BP moved over
move RLen,RecLen ;maximum length of record
camle RLen,Cnt
move RLen,Cnt ;use real length if all fits
sub Cnt,RLen ;update Cnt
;;ok, compute real length, after removing gapchrs, into RRLen
;;maybe leaving the new BP on stack (if there's a gapchr)
move RRLen,RLen
skipge gapchr
jrst DoIt ;dont bother with this if no gapchr
;;ok, there is a gapchr - trim off trailing gapchr's
push p,BP
push p,RLen
Hex2: sojle RLen,Hex3
ildb TT,BP
came TT,gapchr
move RRLen,RLen
jrst Hex2
Hex3: pop p,RLen
subm RLen,RRLen ;RRLen: real record length, minus
aoj RRLen, ;trailing gapchrs
exch BP,(p) ;save the new BP on stack
;;ok, RLen has claimed record len(for updating Addr),
;;RRLen is real number of chars to send in record (having ignored gapchrs)
;;possibly have new BP saved on stack.
;;A has first byte
;;Output record, update addr, BP
DoIt: push p,A
move Chksum,RRLen ;Chksum: checksum
move A,RRLen ? call Hexout ;append length to record buffer
move A,Addr ? lsh A,-10 ;A: high byte of address
addm A,Chksum ? call Hexout ;output it
move A,Addr ? addm A,Chksum ? call Hexout ;low byte of address
addm RLen,Addr ;update address
setz A, ? call Hexout ;output type (00)
pop p,A ;get back the first byte
move B,RRLen ;B: real record length
HexDat: addm A,Chksum ? call Hexout ;output data bytes
sojle B,RecOut
ildb A,BP
jrst HexDat
RecOut: movn A,Chksum ;output negative of checksum
call Hexout
call WrRec ;Note: needs RRLen, clobbers it.
skipl gapchr
pop p,BP ;if doing gap stuff, get real next BP
jumpg Cnt,Hex ;if more to send, do it again
Done: ;;send out the final record
setz A, ? call Hexout ;0 length record
move A,EAddr ? lsh A,-8. ? move Chksum,A ? call Hexout
move A,EAddr ? add Chksum,A ? call Hexout
move A,EType ? add Chksum,A ? call Hexout
movn A,Chksum ? call Hexout
setz RRLen,
jrst WrRec ;write out last record and return
OutOpn: ;;open output file on dskf channel
;;ODEV,OSNAME,OFN1,OFN2 get truenames
came OFN2,[sixbit/>/]
camn OFN2,[sixbit/</]
jrst OutOpY
camn ODEV,[sixbit/TTY/]
jrst OutOpY
syscall OPEN,[%Clbit,,.uii ? %Climm,,dskf
ODEV ? OFN1 ? OFN2 ? OSNAME]
jrst OutOpY
.call ORFNAM
.Lose %LsFil
.close dskf,
syscall OPEN,[%Clbit,,.uai ? %Climm,,dskf ? [sixbit/TTY/]]
.Lose %LsFil
Type "File "
movei A,ODEV
call FilTyp
Type " already exists. Write over it (Y or N)?"
.iot dskf,TT
.close dskf,
caie TT,"Y
cain TT,"y
jrst OutOpY
jrst Die
OutOpY: syscal OPEN,[%Clbit,,.uao ? %Climm,,dskf ? ODEV ? OFN1 ? OFN2 ? OSNAME]
.Lose %LsFil
.call ORFNAM
.Lose %LsFil
return
RdFile: ;;read in file, check DSK8, set up BP and Cnt.
call SNARF
move TT,FILBFR
came TT,[sixbit/DSK8/]
jrst [Type "Not a standard COM file."
jrst Die]
move BP,[440800,,FILBFR+1] ;pointer into file
soj Cnt, ? imuli Cnt,4 ;4 bytes per word
return
SNARF: ;;snarf input file into memory at FILBFR. Allocates pages as needed.
;;IDEV,IFN1,IFN2,ISNAME get updated to truenames.
syscall OPEN,[%Clbit,,.uii ? %Climm,,dskf
IDEV ? IFN1 ? IFN2 ? ISNAME]
jrst [type "Can't open file "
movei A,IDEV
call FilTyp
jrst Die]
syscall RFNAME,[%Climm,,dskf ? %Clout,,IDEV
%Clout,,IFN1 ? %Clout,,IFN2 ? %Clout,,ISNAME]
.Lose %LsFil
syscall fillen,[%Climm,,dskf ? %Clout,,A] ;file length
.Lose %LsFil
jumpe A,[type "Empty input file?"
jrst Die]
movem A,Cnt ;save for future use
addi A,<FILBFR-1>+2000 ;A: last address which we need + 2000
lsh A,-12 ;A: number of pages we need
movei TT,<FILBFR_-12>+1 ;TT: first page we need to get
subm TT,A ;A: -<number of pages to get>
jumpe A,SNARF0 ;if fits in what we have, done
hrl TT,A ;TT: -#pages to get,,first page to get
syscal corblk,[%Climm,,%Cbprv ;Get fresh pages
%Climm,,%Jself
TT
%Climm,,%Jsnew]
jrst [Type "Can't get enough memory"
jrst Die]
SNARF0: move A,[444400,,FILBFR] ;A: BP to first file address
move TT,Cnt ;number of words
Syscal siot,[%Climm,,dskf ? A ? TT] ;Inhale file
.Lose %LsFil
jumpg TT,[Type "SIOT lost!?!? Couldn't read in whole file! Try again."
jrst Die]
.close dskf,
return
IDEV: sixbit/DSK/
IFN1: 0
IFN2: sixbit/COM/
ISNAME: 0
ODEV: sixbit/DSK/
OFN1: 0
OFN2: sixbit/HEX/
OSNAME: 0
;;RFNAME call for Output file
ORFNAM: setz ? sixbit/RFNAME/ ? %Climm,,dskf
%Clout,,ODEV ? %Clout,,OFN1 ? %Clout,,OFN2 ? %Clout,,OSNAME ((setz))
;;SIOT call for tty typeout - TT has length, TT1 has BP
TTYTYP: SETZ ? SIXBIT /SIOT/ ? %Climm,,ttyo ? TT1 ? TT ((SETZ))
Space: 40 ;seems to be used often enough...
CR: ^M
LF: ^J
Quote: 0 ;used inside Jcl parser
Record: ascii/:0000/ ;at most data bytes, so total length of
block 150 ;record is at most 521. chars, i.e.
;151 (105.) words
RecBP: 350700,,Record ;pointer to next chr
RecNum: 0 ;number of records written. For reporting
JCLBuf: Block JCLen
PDList: -PDLen,,PDList
Block PDLen
Variables
Constants
FILBFR: 0 ;final address. File will go here.
END Begin