1
0
mirror of https://github.com/PDP-10/its.git synced 2026-02-15 12:26:27 +00:00

RUG - PDP-11 debugger.

This commit is contained in:
Lars Brinkhoff
2018-07-29 10:32:51 +02:00
parent 27a0022d1b
commit 3f5e1523fc
13 changed files with 5707 additions and 2 deletions

BIN
src/chsncp/rt11m.50 Normal file

Binary file not shown.

846
src/pdp11/defs.126 Normal file
View File

@@ -0,0 +1,846 @@
;;; DEFS - Definitions and configuration data -*-PALX-*-
.nlist
.auxil
;;; Define YES and NO so they're acceptable SETF answers
yes===1
no===0
.macro setf q,a
.if ndf a
.print "q "
.ttymac ans
.if ndf ans
setf ^"Bad input, try again:",a
.mexit
.endc
a==ans
.endm
.endc
.endm
; Define system names for following question
mit===1 ; MIT's PDP 11/34
sao===2 ; SAO's LSI 11/03
lll===3
mit44==4 ; MIT's new PDP 11/44
drl===1 ; RL01 type disk drives
drk===2 ; RK05 type disk drives
drp===3 ; RP11 type disk drives
setf ^"System (MIT, MIT44, SAO, or LLL)?",sys
;define some appropriate macros
.if eq <sys-mit>*<sys-mit44>
.macro ifMIT code
code
.endm
.macro ifSAO code
.endm
.macro ifLLL code
.endm
.macro ifOTHER code
.endm
.endc ; eq <sys-mit>*<sys-mit44>
.if eq sys-sao
.macro ifMIT code
.endm
.macro ifSAO code
code
.endm
.macro ifLLL code
.endm
.macro ifOTHER code
.endm
.endc ; eq sys-sao
.if eq sys-lll
.macro ifMIT code
.endm
.macro ifSAO code
.endm
.macro ifLLL code
code
.endm
.macro ifOTHER code
.endm
.endc ; eq sys-lll
.if ne <<sys-mit>*<sys-mit44>*<sys-lll>*<sys-sao>>
.macro ifMIT code
.endm
.macro ifSAO code
.endm
.macro ifLLL code
.endm
.macro ifOTHER code
code
.endm
.endc ; all other systems
.sbttl Math Department's PDP 11/34 system
.if eq sys-mit
ifMIT <
; Define CPU model
pdp11==34 ; PDP11/34
havswr===1 ; presume it has swr, check at runtime now
sysdsk===drl ; presume RL01s from henceforth
.print "Are you sure you want to assemble for a machine you don't have??"
; No. of various devices
nrk==0 ; RK11
nrx==0 ; RX11
nrl==2 ; RL11
nrp==0 ; RP11
ncr==0 ; CR11
nlp==1 ; LPT
ndp==0 ; DP11
ndu==1 ; DU11
; No. of various terminal interfaces
ndz==1 ; DZ11
nkl==0 ; KL11, DL11-A,-B
ndl==4 ; DL11-C,-D,-E
ndc==1 ; DC11 (for simulator)
; Various options
pfail===1 ; assemble power fail code
>
.endc
.sbttl Math Department's PDP 11/44 system
.if eq sys-mit44
ifMIT <
; Define CPU model
pdp11==44 ; PDP11/44
havswr===1 ; it has switch register
;;; find out what disk to use
setf ^"System disk (drp, drl, drk)?",sysdsk
; No. of various devices
nrk==0 ; RK11
nrx==0 ; RX11
nrl==2 ; RL11
nrp==0 ; RP11
ncr==0 ; CR11
nlp==1 ; LPT
ndp==0 ; DP11
ndu==1 ; DU11
.if eq <sysdsk-drp>
nrp==1 ; have an RP11
nrl==0 ; have no RL11
.endc
; No. of various terminal interfaces
ndz==1 ; DZ11
nkl==0 ; KL11, DL11-A,-B
ndl==4 ; DL11-C,-D,-E
ndc==1 ; DC11 (for simulator)
; Various options
pfail===0 ; don't assemble power fail code
>
.endc
.sbttl Orszag's LSI11 system
ifSAO <
; Define CPU model
pdp11==03 ; LSI11
sysdsk===0
; No. of various devices
nrk==0 ; RK11
nrx==1 ; RX11
nrl==0 ; RL11
nrp==1 ; RP11
ncr==0 ; CR11
nlp==1 ; LPT (well, actually a terminet kludge..)
ndp==0 ; DP11
ndu==1 ; DU11
; Maximum no. of various terminal interfaces
ndz==0 ; DZ11
nkl==3 ; KL11, DL11-A,-B
ndl==2 ; DL11-C,-D,-E
ndc==0 ; DC11
; Various options
pfail===0 ; no power fail code
>
.sbttl LLL (S1 project LSI-11)
ifLLL <
; Define CPU model
pdp11==03 ; LSI11
sysdsk===0
; No. of various devices
nrk==0 ; RK11
nrx==1 ; RX11
nrl==0 ; RL11
nrp==0 ; RP11
ncr==0 ; CR11
nlp==1 ; LPT
ndp==0 ; DP11
ndu==0 ; DU11
; Maximum no. of various terminal interfaces
ndz==0 ; DZ11
nkl==1 ; KL11, DL11-A,-B
ndl==0 ; DL11-C,-D,-E
ndc==0 ; DC11
; Various options
pfail===0 ; no power fail code
>
.sbttl Configuration calculations
; Floating vector address calculation
ifSAO <
dpv==0 ; no DP11
dzv==0 ; no DZ11
klv==300 ; DLV11-J first vector interrupt address
dlv==330 ; DLV11s from here on
duv==350 ; DUV11
>
ifMIT <
dpv==300 ; DP11
klv==0 ; no KL11, DL11-A,-B
dlv==310 ; DL11-C,-D,-E
dzv==350 ; DZ11
duv==360 ; DU11
>
; Floating address calculation
ifSAO <
duaddr==160010 ; address of 1st DU11
dzaddr==0 ; no DZ11
>
ifMIT <
duaddr==160010 ; address of 1st DU11
dzaddr==160020 ; address of 1st DZ11
>
.sbttl Register definitons
r0=%0
r1=%1
r2=%2
r3=%3
r4=%4
r5=%5
sp=%6
pc=%7
.xcref r0,r1,r2,r3,r4,r5,sp,pc
; Assume a switch register for most cpus, none for 11/03 and ask for 11/34.
.if ndf havswr
.iif eq pdp11-03, havswr===0
.iif eq pdp11-34, setf ^"Does your 11/34 have the real programmer's console?",havswr
.endc
.iif eq pdp11-44, havswr===1 ; PDP11/44 has a switch register!!!
.iif ndf havswr, havswr===1
.if ne havswr
swr==177570 ; switch register
.endc
.lif ne pdp11-03
ps==177776 ; processor status word
.if ndf memman
.iif eq <pdp11-10>*<pdp11-20>, memman===0
.ielse memman===1
.endc
.if ndf eis
.iif eq <pdp11-10>*<pdp11-20>, eis===0
.ielse eis===1
.endc
pr0==000 ; processor priority definitions
pr1==040
pr2==100
pr3==140
pr4==200
pr5==240
pr6==300
pr7==340
.lif ne pdp11-03
lks==177546 ; line clock
tks==177560 ; console tty registers
tkb==177562
tps==177564
tpb==177566
.if ne nrk
rkdsr==177400 ; RK11 disk registers
rkerr==177402
rkcsr==177404
rkwcr==177406
rkbar==177410
rkdar==177412
.endc
.if ne nrl
rlcsr==174400 ; RL11 disk registers
rlbar==174402
rldar==174404
rlmpr==174406
.endc
.if ne nrp
rpcou1==176700
rpcou2==176702
rpcou3==176704
rpcou4==176706
rpdsr==176710
rperr==176712
rpcsr==176714
rpwcr==176716
rpbar==176720
rpcar==176722
rpdar==176724
rpm1r==176726
rpm2r==176730
rpm3r==176732
rpsucr==176734
rpsilo==176736
.endc
.if ne nrx
rxcs==177170 ; floppy disk control/status register
rxdb==177172 ; floppy disk data buffer register
.endc
.if ne nlp
lps==177514
lpb==177516
lvs==177510
lvb==177512
.endc
.sbttl Instruction macros
.if ne pdp11-03
.if ne pdp11-34
; MTPS and MFPS macros simulate PS intructions on 11/03 (LSI)
; and 11/34 processors.
.macro mtps src
movb src,@#ps
.endm
.macro mfps dst
movb @#ps,dst
.endm
.endc
.endc
.if ne pdp11-44
.if ne pdp11-45
.if ne pdp11-70
; SPL macro changes the the priority to its argument. It
; (unfortunately) does this with a MOV, thus clobbering
; the condition codes and such.
.macro spl n
.iif ne n, mtps #n*40
.else
.iif eq pdp11-03, mtps #0
.ielse clrb @#ps
.endc
.endm
.endc
.endc
.endc
.if eq <pdp11-10>*<pdp11-20>
; SOB macro expands into code which performs identically to
; the SOB instruction found on more powerfull 11 processors
.macro sob r,addr
dec r
bne addr
.endm
; RTT macro expands into a RTI. This is so RTTs can be used in
; places where they would be called for on 11/40s, 11/45s etc.
.macro rtt
rti
.endm
; XOR macro simulates XOR instruction on 11/45.
; Caution: this macro is not intended to work with
; (Rn)+, -(Rn) or (SP) destinations.
.macro xor r,d
mov r,-(sp)
bic d,(sp)
bic r,d
bis (sp)+,d
.endm
; SXT macro performs sign extend as on PDP11/45.
.macro sxt d
if mi,<
mov #-1,d
>
else <
clr d
>
.endm
.endc ; eq <pdp11-10>*<pdp11-20>
.if eq eis
; ASH macro generates a series of ASR or ASL instructions to
; simulate the 11/45 ASH instruction.
.macro ash src,r
.ntype %.m,r
.iif ne %.m&70, .error ASH dst must be register
.ntype %.m,src
.iif ne %.m-27, .error ASH macro must have constant shift
%.m===0'src
.if ge %.m
.rept %.m
asl r
.endr
.iff
.rept -%.m
asr r
.endr
.endc
.endm
; MUL macro generates call to either MUL1 or MUL2 depending upon
; whether register destination is even or odd. Simulates 11/45 MUL.
.macro mul src,r
.ntype %.m,r
.iif ne %.m&70, .error MUL dst must be register
push src,r
.iif ne %.m&1, jsr r5,mul1
.ielse jsr r5,mul2
pop r
.iif eq %.m&1, pop r+1
.endm
; DIV macro generates call to DIV2 to simulate 11/45 DIV instruction.
.macro div src,r
.ntype %.m,r
.iif ne %.m&70, .error DIV dst must be register
push r,r+1,src
jsr r5,div2
pop r+1,r
.endm
.endc ; eq eis
.sbttl Random macros
.macro push a0,a1,a2,a3,a4,a5,a6,a7
.irp d,<a0,a1,a2,a3,a4,a5,a6,a7>
.if idn d,#0
clr -(sp)
.iff
.lif nb d
mov d,-(sp)
.endc
.endm
.endm push
.macro pop a0,a1,a2,a3,a4,a5,a6,a7
.irp d,<a0,a1,a2,a3,a4,a5,a6,a7>
.if idn d,*
tst (sp)+
.iff
.lif nb d
mov (sp)+,d
.endc
.endm
.endm pop
.macro typval text
.print ïtextŠ
.endm
; .EXIT bootloads BOOT.
.macro .exit
ifMIT < reset
mov #174400,r0
tstb (r0)
bpl .-2
mov #13,4(r0)
mov #4,(r0)
tstb (r0)
bpl .-2
mov #77601,4(r0)
mov #6,(r0)
tstb (r0)
bpl .-2
mov #177400,6(r0)
mov #0,4(r0)
mov #0,2(r0)
mov #14,(r0)
tstb (r0)
bpl .-2
clr pc
>
ifSAO <
jmp @#173000
>
ifOTHER < ; all other systems, jump to hardware boot
.iif ndf asmrt1, asmrt1===0 ; if we don't know what asmrt1 is default to 0
.if eq asmrt1
jmp @#173000
.iff
mov pc,r0 ; don't do an HRESET, we can be restarted
emt 350 ; return to rt-11
>
.endm
; DSECT defines a dummy section, used to define symbols
; that are offsets from a register (or some other variable).
; An optional second argument is set to length of structure.
; Example of use:
; DSECT < PCBNEXT: 0 ;PCBNEXT=0
; PCBLAST: 0 ;PCBLAST=2
; PCBFOOO: 0
; >
.macro dsect sect,len
.if p1 ; define symbols only on pass 1
%.dtmp===.
.=0
sect
.iif nb len, len==.
.=%.dtmp
.endc
.endm
; Text accumulation macros. TXTINT creates a text segment of the
; specified name. APPEND appends text to that segment. To insert the
; accumulated text into the assembly merely use the segment's name.
.macro txtint name
.macro name op1,op2,op3
op1'op2
op3
.endm name
.endm txtint
.macro append name,newcft
.nlist
name ^|.macro name op1,op2,op3
op1|,^|newcft'op2
op3|,.endm
.list
.endm append
.sbttl Flow of control macros
; IF macro: Generates code that executes the if clause
; if the specified conditon is true, the else clause if
; it is false. The else clause is not required. Example:
; if eq,<
; mov r0,r1
; mov (r1)+,r2
; >
; else <
; jsr pc,foo
; >
.macro if cond,code
.nlist
gncnt===gncnt+1
.irp foo,\gncnt
.iif p1, .word 0
.else
%.itmp===<g'foo-<.+2>>/2
.iif gt %.itmp-377, .error Branch out of range
.iif lt %.itmp+377, .error Branch out of range
.iif eq <b'cond>&400, <b'cond>+%.itmp+400
.ielse <b'cond>+%.itmp-400
.endc
code
g'foo===.
ifcnt===foo
.endm .irp
.list
.endm if
.macro else code
gncnt===gncnt+1
.irp foo,\ifcnt
.irp bar,\gncnt
br g'bar
g'foo===.
code
g'bar===.
.endm
.endm
.endm else
gncnt===777 ; gensym count
; LOOP macro allows loops without labels. Use RPTL and EXITL
; to repeat loop and exit loop. Both take branch condition arguments.
; If condition arg is null, then BR is used, i.e. unconditional.
; End of CODE falls out of loop unless specific RPTL is used.
; Example of LOOP macro:
; loop < cmpb r0,(r1)+ ; found char yet?
; exitl eq ; exit loop on equal
; inc r2 ; not found
; cmp r2,r5 ; too many?
; rptl lt ; no, keep going
; jmp error ; too many
; >
; ; EXITL comes here
; LOOP defines two lables around the code argument,
; the first for looping back via the RPTL macro, the
; second for exiting the loop via the EXITL macro.
; Labels are of the form %Ln or %Xn where n signifies
; that this is the nth use of the LOOP macro. %Yv
; gives the loop number of the v'th level of nesting.
; Up to 7 levels of nesting are allowed.
%level===0
%loopn===0
.macro loop code
%loopn===%loopn+1
.if gt %loopn-7777
.error Too many loops (maximum of 4095)
.mexit
.endc
%level===%level+1
.if gt %level-7
.error Loop depth exceeds 7
.mexit
.endc
.irp n,\%level
%y'n===%loopn
.endm
.irp n,\%loopn
%l'n===. ; loop back to here
code
%x'n===. ; exit to here
.endm
%level===%level-1
.endm loop
.macro rptl cond
.if eq %level
.error RPTL not inside LOOP
.mexit
.endc
.irp n1,\%level
.irp n2,\%y'n1
.iif b cond, br %l'n2
.ielse b'cond %l'n2
.endm
.endm
.endm rptl
; SORL expands into a SOB instruction back to the last LOOP
; point. SORL takes one arg, a register to use with the SOB
; instruction.
.macro sorl r
.if eq %level
.error SORL not inside LOOP
.mexit
.endc
.irp n1,\%level
.irp n2,\%y'n1
sob r,%l'n2
.endm
.endm
.endm sorl
.macro exitl cond
.if eq %level
.error EXITL not inside LOOP
.mexit
.endc
.irp n1,\%level
.irp n2,\%y'n1
.iif b cond, br %x'n2
.ielse b'cond %x'n2
.endm
.endm
.endm exitl
.sbttl Literal macros
; Literal macros -- deposit literals into contants area which
; will have length %.clen.
.iif p1, %.clen===0 ; start off length 0
; .LITRL macro will store a literal -- a block of code that
; is the first argument to .LITRL. The literal is stored in
; the constant area at %.CONSTA, and will be forced to an even
; address. If there is no second argument the pointer to the
; literal will be stored inline; if there is a second arg the
; second arg will be set to the literal's pointer value.
; For example:
; The following stores a pointer to a string of bytes (0,1,2...)
; at location foo:
; foo: .litrl ^"
; .byte 0,1,2,3,4,5"
; The following sets foo to a pointer to a block of words and
; bytes (0,1,2,...):
; .litrl ^"
; .word 0,1,2
; .byte 3,4,5",foo
.macro .litrl litarg,litptr
.nlist
.if p1
%.ctmp===.
.even
litarg ; stick literal here now so can find its length
%.clen===<<%.clen+1>&177776>+.-<<%.ctmp+1>&177776>
.=%.ctmp
.iff
%.ctmp===.
.=%.consta
.even
%.cadr===.
litarg ; actual storage of literal
%.consta===.
.=%.ctmp
.endc
.if b litptr
.even
.word %.cadr-. ; deposit ptr to literal
.iff
litptr==%.cadr ; set ptr to pt to literal
.endc
.list
.endm
; The .STRING macro stores an asciz string in the constants area,
; at %.CONSTA, and either stores the pointer to that string
; at the .STRING, or sets a value (if there is a second arg).
; For example, the following stores, at FOO, a relative pointer
; to the asciz string "hello":
; FOO: .string ^"hello"
; The following sets foo to a pointer to asciz string "hello":
; .string ^"hello",foo
.macro .string text,strptr
.nlist
.if p1
%.clen===%.clen+.length ^ïtext¬+1
.iff
%.ctmp===.
.=%.consta
%.cadr===.
.asciz ïtextŠ
%.consta===.
.=%.ctmp
.endc
.if b strptr
.word %.cadr-.
.iff
strptr==%.cadr
.endc
.list
.endm
; CONSTANTS causes space to be allocated for the constants
; generated by .LITRL and .STRING
.macro constants
.nlist
.even
%.consta===. ; constants will be assembled here.
.=.+%.clen ; reserve space for them.
.even
.if p1
.if gt %.clen
.print "
Constants area "
typval \%.clen
.print " bytes,
From "
typval \%.consta
.print " to "
typval \.-1
.print " inclusive.
"
.endc
.endc
.list
.endm constants

3741
src/pdp11/rug.526 Normal file

File diff suppressed because it is too large Load Diff

411
src/pdp11/sadisk.28 Normal file
View File

@@ -0,0 +1,411 @@
; -*-PALX-*-
.sbttl Disk i/o
.iif ndf asmpr, asmpr==0 ; assume we can't print if we don't know how
.if eq sysdsk-drk
lblk==512. ; no. of bytes per sector
nsecto==12. ; no. of sectors per track
ntrack==406. ; no. of tracks per disk
.endc
.if eq sysdsk-drl
lblk==256. ; no. of bytes per sector
nsecto==40. ; no. of sectors per track
ntrack==256. ; no. of tracks per disk
.endc
.if ne nrx
lblk==128. ; no. of bytes per sector
nsecto==26. ; no. of sectors per track
ntrack==77. ; no. of tracks per disk
.endc
; DOPENR sets up for reading from disk.
dopenr: mov 2(sp),dblock ; set block no. to first block to read
clr dbufc ; no characters in buffer yet
pop (sp) ; remove arg from stack
rts r5
; DOPENW sets up for writing to disk.
dopenw: mov 2(sp),dblock ; set block no. to first block to write
mov #lblk,dbufc ; room for 512 (or 256) characters in block
mov pc,-(sp) ; set DBUFP to DBUF
add #dbuf-.,(sp) ; ...
mov (sp)+,dbufp ; ...
pop (sp) ; remove arg from stack
rts r5
; DCLSW finishes up writing to the disk.
dclsw: cmp dbufc,#lblk ; something in buffer?
if ne,<
loop < clrb @dbufp ; clear remainder of buffer
inc dbufp
dec dbufc
rptl ne
>
push dblock ; DKWRIT arg: block no.
jsr r5,dkwrit ; write out block
>
rts r5
; DGETW reads a word from the disk.
dgetw: push (sp) ; make room for return val
jsr r5,dgetb ; read low byte
movb (sp)+,2(sp)
jsr r5,dgetb ; read high byte
movb (sp)+,3(sp)
rts r5
; DGETB reads a byte from the disk.
dgetb: push (sp) ; make room for return val
dec dbufc ; characters left to read in this block?
if mi,< ; none left, read next block
push dblock ; DKREAD args: block no.
jsr r5,dkread ; read block
inc dblock ; increment block no.
mov #lblk-1,dbufc ; 511 (or 255) bytes left to read
mov pc,-(sp) ; set DBUFP to DBUF
add #dbuf-.,(sp) ; ...
mov (sp)+,dbufp ; ...
>
clr 2(sp) ; so high byte will be zero
movb @dbufp,2(sp) ; get character
inc dbufp ; move ptr to next
rts r5
; DPUTW writes a word to the disk.
dputw: push 2(sp) ; DPUTB arg: byte
jsr r5,dputb ; write low byte
swab 2(sp) ; switch bytes and fall through
; to write high byte
; DPUTB writes one byte to the disk.
dputb: movb 2(sp),@dbufp ; store character in buffer
inc dbufp ; move ptr to next character slot
dec dbufc ; buffer filled?
if eq,< ; yes, write it out
push dblock ; DKWRIT args: block no.
jsr r5,dkwrit ; write out this block
inc dblock ; increment block no.
mov #lblk,dbufc ; room for 512 (or 256) more characters
sub #lblk,dbufp ; set DBUFP to DBUF
>
pop (sp) ; remove arg from stack
rts r5
.if eq sysdsk-drk
dkread: push (sp)
mov #5,2(sp)
br rkrw
dkwrit: push (sp)
mov #3,2(sp)
br rkrw
.endc
.if eq sysdsk-drl
dkread: push (sp)
mov #14,2(sp)
br rlrw
dkwrit: push (sp)
mov #12,2(sp)
br rlrw
.endc
.if ne nrx
dkread: br rxread
dkwrit: br rxwrit
.endc
.sbttl RL11 read/write
; RLRW
;
; ARGS: VALS:
; SP ->op code (none)
; block number
.if eq sysdsk-drl
rlrw: jsr r5,save6 ; save registers
mov 20(sp),r1 ; get block number
clr r0 ; clear track counter
mov #40.,r2 ; there are 40. blocks per track
div r2,r0 ; get number of tracks in r0
ash #6,r0 ; mov into place for Cylinder address
bis r1,r0 ; merge sector (in r1) with track
mov r0,20(sp) ; save converted disk address
mov pc,r1 ; pointer to DBUF
add #dbuf-.,r1 ; ...
mov #7,r4 ; number of times to try recoverable errors
;
; reset the drive
;
loop < mov #rlcsr,r5 ; get address of CSR
mov #13,4(r5) ; do a get status/reset drive
mov #4,(r5) ; perform function
loop < tstb (r5) ; has drive finished yet??
rptl pl ; no yet
>
tst (r5) ; check for errors
bmi rlerr ; go handle them
jsr pc,rlseek ; seek to the right track
; Now we can finally do the read/write operation!!!!!!!!!
mov #-<lblk/2>,6(r5) ; set word count
mov r1,2(r5) ; set bus address
mov 20(sp),4(r5) ; set disk address
mov 16(sp),(r5) ; perform function
loop < tstb (r5) ; is the controller finished???
rptl pl ; not yet if plus
>
tst (r5) ; test for errors
exitl pl ; no error, we're through
bit #140000,(r5) ; see if a disk error
bne rlerr ; check out disk errors
sorl r4 ; try a few more times
br rlerr
>
jsr r5,rest6 ; restore registers
pop (sp),(sp) ; remove args from stack
rts r5
; perform a seek on the disk to the right track
rlseek: push r0,r1,r2 ; save registers
mov #10,(r5) ; execute read headers function
loop < tstb (r5) ; has drive finished yet????
rptl pl ; not yet
>
mov 6(r5),r0 ; get current disk address
mov 20+10(sp),r1 ; get desired disk address
bic #77,r1 ; clear sector bits
bic #177,r0 ; clear sector and surface bits
mov r1,r2 ; copy desired disk address
bic #177677,r2 ; isolate surface bit
ash #-2,r2 ; position it for difference word in seek
bic #100,r1 ; remove surface bit
sub r1,r0 ; find difference word for seek operation
bcc 1$ ; if CC actual >= desired position
neg r0 ; make positive difference
bis #4,r0 ; set bit to indicate move towards disk center
1$: inc r0 ; set marker bit
bis r2,r0 ; merge in surface bit
mov r0,4(r5) ; put difference word into RLDAR
mov #6,(r5) ; perform a seek function
loop < tstb (r5) ; has controller finished
rptl pl ; not yet
>
pop r2,r1,r0 ; restore registers
rts pc
; perform error checking on the disk drive
rlerr:
.if ne asmpr
print ^"
RL01 disk error -- operation aborted
"
.endc
jmp dskerr
.endc ;eq sysdsk-drl
; RKRW performs disk transfers of one sector. It takes two args:
; the block no. and operation code (3 for write, 5 for read).
; ARGS: VALS:
; SP -> op code (none)
; block no.
.if eq sysdsk-drk
rkrw: jsr r5,save6 ; save regs
clr r0 ; divide block no. by 12
mov 20(sp),r1 ; ...
div #12.,r0 ; ...
ash #4,r0 ; multiply quotient by 16
add r1,r0 ; add remainder to get DAR
bis rknum,r0 ; put in disk no.
mov pc,r1 ; ptr to DBUF
add #dbuf-.,r1 ; ...
mov #7,r5 ; no. of times to retry recoverable errors
loop < mov #rkcsr,r4 ; ptr to RKCSR
mov #1,(r4) ; controller reset
loop < tstb (r4) ; wait for done
rptl pl
>
mov #rkdar+2,r4 ; ptr to RKDAR + 2
mov r0,-(r4) ; set RKDAR
mov r1,-(r4) ; set RKBAR
mov #-<lblk/2>,-(r4) ; set RKWCR
mov 16(sp),-(r4) ; set RKCSR, i.e. perform operation
loop < tstb (r4) ; wait for done
rptl pl
>
tst (r4) ; errors?
exitl pl
bit #166340,-(r4) ; recoverable error?
if eq,<
sorl r5 ; yes, try a few times
>
.if ne asmpr
print ^"
Disk Error -- operation aborted
"
.endc
jmp dskerr
>
jsr r5,rest6 ; restore regs
pop (sp),(sp) ; remove args from stack
rts r5
rknum: .word 0 ; Using disk number zero because
; disk no. 1 (fixed) is not formatted
.endc
.sbttl RX11 read/write
.if ne nrx
; RXREAD
; ARGS: VALS:
; SP -> block no. (none)
rxread: push r0,r1,r2 ; save regs
mov #rxcs,r0 ; get bus address of RX11 controller
push 10(sp),#7 ; RXRW args: block no., op code
bis rxnum,(sp) ; yes, set unit select in op code
jsr r5,rxrw ; initiate read
loop < bit #40,(r0) ; wait for Done
rptl eq
>
tst (r0) ; Error?
bmi rxer
mov #10,r2 ; no. of times to retry parity errors in Empty
loop < mov #3,(r0) ; send Empty command
mov pc,r1 ; ptr to buffer
add #dbuf-.,r1 ; ...
loop < bitb #240,(r0) ; test Transfer Request and Done bits
rptl eq ; wait for one to set
exitl pl ; Done?
movb 2(r0),(r1)+ ; no, Transfer Request, copy data byte
rptl
>
tst (r0) ; Error (parity error in transfer from buffer)?
exitl pl
sorl r2 ; retry Empty operation
br rxer
>
pop r2,r1,r0,(sp) ; restore regs, remove arg from stack
rts r5
; RXWRIT writes a block on the floppy.
; ARGS: VALS:
; SP -> block no. (none)
rxwrit: push r0,r1,r2 ; save regs
mov #rxcs,r0 ; get bus address of RX11 controller
mov #10,r2 ; no. of times to retry parity errors in Fill
loop < mov #1,(r0) ; send Fill command
mov pc,r1 ; get ptr to buffer
add #dbuf-.,r1 ; ...
loop < bitb #240,(r0) ; test Transfer Request and Done bits
rptl eq
exitl pl ; Done?
movb (r1)+,2(r0) ; no, Transfer Request, load data byte
rptl
>
tst (r0) ; Error (parity error in transfer to buffer)?
exitl pl
sorl r3 ; retry Fill
br rxer
>
push 10(sp),#5 ; RXRW args: block no., op code
bis rxnum,(sp) ; yes, set unit select in op code
jsr r5,rxrw ; initiate write
loop < bit #40,(r0) ; wait for Done
rptl eq
>
tst (r0) ; Error?
bmi rxer
pop r2,r1,r0,(sp) ; restore regs, remove arg from stack
rts r5
; RXRW issues a read or write command to the RX11. If writing, the RX11
; buffer should already be filled with the stuff to be written. If reading
; the RX11 buffer should be emptied afterward. RXRW does not wait for the
; read or write operation to complete.
; ARGS: VALS:
; SP -> op code (none)
; block no.
rxrw: push r2,r3 ; save regs
clr r2 ; divide block no. by 26 to get track
mov 10(sp),r3 ; and sector addresses
div #nsecto,r2 ; perform the division
asl r3
cmp r3,#nsecto
if his,<
sub #nsecto-1,r3
>
inc r3 ; make sector address one based
loop < bit #40,(r0) ; wait for Done
rptl eq
>
mov 6(sp),(r0) ; send read or write command
loop < tstb (r0) ; wait for Transfer Request
rptl pl
>
mov r3,2(r0) ; send Sector address
loop < tstb (r0) ; wait for Transfer Request
rptl pl
>
mov r2,2(r0) ; send Track address
pop r3,r2,(sp),(sp) ; restore regs, remove args from stack
rts r5
rxer: mov @#rxdb,r0
bit #1,r0
if ne,<
.if ne asmpr
print ^"
CRC error detected reading diskette."
.endc
>
bit #2,r0
if ne,<
.if ne asmpr
print ^"
Parity error detected on command or address data being transfered to RX01."
.endc
>
.if ne asmpr
jmp dskerr
.iff
pop r2,r1,r0,(sp)
rts r5
.endc
rxnum: .word 0 ; disk no.
.endc ; ne nrx
dbuf: .blkb lblk ; disk sector buffer
dblock: .word 0 ; block no. for next disk i/o
dbufp: .word 0 ; ptr to next byte in disk buffer to read/write
dbufc: .word 0 ; read: no. of characters remaining in buffer
; write: room left in buffer

275
src/pdp11/stuff.34 Normal file
View File

@@ -0,0 +1,275 @@
; STUFF - Very basic useful stuff -*-PALX-*-
stvn==%fnam2
.sbttl Register save/restore routines
; SAVE6 routine saves R0 through R5 on stack, R0 at top:
; SP -> R0
; R1
; R2
; R3
; R4
; R5
; Call by JSR R5,SAVE6. Restore regs by REST6 routine.
save6: push r4,r3,r2,r1,r0 ; R5 already on stack by JSR.
jmp (r5) ; return.
; REST6 routine restores R0 through R5 from stack, where
; R0 is considered to be the top word of the stack (which is
; how SAVE6 pushes the registers). Call by JSR R5,REST6.
; REST6 returns with the 6 words popped off the stack.
rest6: tst (sp)+ ; forget old R5 contents.
pop r0,r1,r2,r3,r4 ; restore other regs.
rts r5 ; return and restore R5.
.sbttl Multiply & Divide
.if eq eis
; MUL1 multiplies two integers, producing a single precision product. Both the
; multiplicand and multiplier are treated as signed numbers. This routine is
; meant to be compatible with the single precision multiply instruction found
; on reasonable PDP11s.
; ARGS: VALS:
; SP -> A SP -> P
; B
mul1: push r1,r2 ; save regs
mov 6(sp),r1 ; multiplicand
mov 10(sp),r2 ; multiplier
clr 10(sp) ; clear product accumulator
loop < ror r2 ; divide multiplier by 2, testing lowest bit
exitl eq ; nothing left
if cs,<
add r1,10(sp) ; if bit is 1 then add multiplicand to product
>
asl r1 ; double multiplicand
clc ; so ROR is logical shift
rptl ; and repeat.
>
if cs,<
add r1,10(sp) ; one last add necessary if low bit was 1
>
pop r2,r1,(sp) ; restore regs, remove arg2 from stack
rts r5
; MUL2 is multiplies two integers producing a double precision product. Both
; the multiplicand and multiplier are treated as signed numbers. This routine
; is meant to be compatible with the double precision multiply instruction
; found on reasonable PDP11s.
; ARGS: VALS:
; SP -> multiplicand SP -> P hi
; multiplier P lo
mul2: push r0,r1,r2 ; save regs
clr r0 ; multiplicand
mov 10(sp),r1 ; ...
if mi,<
com r0 ; if low part negative set high part to -1
>
mov 12(sp),r2 ; multiplier
if mi,<
neg r2 ; negate multiplier and multiplicand
neg r0 ; double word negate
neg r1 ; ...
sbc r0 ; ...
>
clr 10(sp) ; clear product accumulator
clr 12(sp) ; ...
loop < asr r2 ; divide multiplier by 2, testing lowest bit
exitl eq ; nothing left
if cs,<
add r1,12(sp) ; if bit is 1 then add multiplicand to product
adc 10(sp) ; ...
add r0,10(sp) ; ...
>
asl r1 ; double multiplicand
rol r0 ; ...
rptl
>
if cs,<
add r1,12(sp) ; one last add necessary if low bit was 1
adc 10(sp) ; ...
add r0,10(sp)
>
pop r2,r1,r0 ; restore regs
rts r5
; DIV2 divides a double word quantity by a single word quantity yielding a
; quotient and remainder. It is meant to simulate the DIV instruction found
; on reasonable 11s.
; ARGS: VALS:
; SP -> divisor SP -> remainder
; dividend lo quotient
; dividend hi
div2: jsr r5,save6 ; save regs
mov 22(sp),r0 ; dividend hi
mov 20(sp),r1 ; dividend lo
mov 16(sp),r2 ; divisor
if mi,<
neg r2 ; negate divisor and dividend
neg r0 ; double word negate
neg r1 ; ...
sbc r0 ; ...
>
clr r3
mov #16.,r4
loop < asl r3
rol r1
rol r0
cmp r2,r0
if le,<
sub r2,r0
inc r3
>
sorl r4
>
mov r3,22(sp)
mov r0,20(sp)
jsr r5,rest6
pop (sp)
rts r5
.endc ; eq eis
; DMUL performs double precision multiplication. Both multiplicand and
; multiplier are treated as unsigned integers. This routine is necessary
; because the PDP11 multiply instruction is too crufty for some things.
; ARGS: VALS:
; R0,R1: multiplicand R0,R1: product
; R2: multiplier
dmul: push r3,r4 ; save regs
mov r0,r3 ; copy multiplicand
mov r1,r4 ; ...
clr r0 ; clear product accumulator
clr r1 ; ...
loop < clc ; clear carry so ROR is logical shift
ror r2 ; divide multiplier by 2, testing lowest bit
exitl eq ; nothing left
if cs,<
add r4,r1 ; if bit is 1 then add multiplicand to product
adc r0 ; ...
add r3,r0 ; ...
>
asl r4 ; double multiplicand
rol r3 ; ...
rptl
>
if cs,<
add r4,r1 ; one last add necessary if low bit was 1
adc r0 ; ...
add r3,r0 ; ...
>
pop r4,r3 ; restore regs
rts r5
; DDIV performs double precision division. It is best suited to dividing
; double precision no.s by some constant. Both dividend and divisor are
; treated as unsigned integers. This routine is necessary because the PDP11
; divide instruction is too crufty for just about anything.
; ARGS: VALS:
; R0,R1: dividend R0,R1: quotient
; R2,R3: divisor normalized R2: remainder
; R4,R5: 1 shifted same
; Note: DDIV is called by JSR PC,DDIV.
ddiv: clr -(sp) ; start quotient at 0
clr -(sp) ; ...
loop < cmp r2,r0
blo 1$
if eq,<
cmp r3,r1
if los,<
1$: sub r3,r1 ; subtract from dividend
sbc r0
sub r2,r0
bis r4,2(sp)
bis r5,(sp)
>
>
clc
ror r2
ror r3
asr r4
ror r5
rptl ne
tst r4
rptl ne
>
mov r1,r2 ; put remainder in r2
pop r1,r0 ; put quotient in r0,r1
rts pc
; DIV10 divides r0,r1 by 10, remainder in r2. Clobbers r3, r4, and r5.
; Call with JSR PC,DDIV10.
ddiv10: mov #120000,r2 ; 10 normalized
clr r3 ; ...
mov #10000,r4 ; 1 shifted same amount as 10
clr r5 ; ...
jmp ddiv ; jump to common double precision divide
; DIV24 divides r0,r1 by 24, remainder in r2. Clobbers r3, r4, and r5.
; Call with JSR PC,DDIV24.
ddiv24: mov #140000,r2 ; 24 normalized
clr r3 ; ...
mov #4000,r4 ; 1 shifted same amount as 24
clr r5 ; ...
jmp ddiv ; call common double precision divide
; DIV60 divides r0,r1 by 60, remainder in r2. Clobbers r3, r4, and r5.
; Call with JSR PC,DDIV60.
ddiv60: mov #170000,r2 ; 60 normalized
clr r3 ; ...
mov #2000,r4 ; 1 shifted same amount as 60
clr r5 ; ...
jmp ddiv ; call common double precision divide
.sbttl random things
bits: .byte 1,2,4,10,20,40,100,200
.if ne ndz
ifMIT <
; DZ11 line parameters
; 10000=Reciever clock on
; 7400=speed, 4 bits: low order bits
; 00 01 10 11
; ----------------------
; high 00| 50 75 110 134.5
; order 01| 150 300 600 1200
; bits 10| 1800 2000 2400 3600
; 11| 4800 7200 9600 19.2K
; 200=odd parity
; 100=parity enabled
; 40=stop code (on is 2 stop bits)
; 30=character length, excluding parity, 00=5,01=6,10=7,11=8
; 7=line number
dzlpar: 17120 ; line 0: 9600 baud, even parity, 7 bits (SB)
17121 ; line 1: 9600 baud, even parity, 7 bits (VT52 #1)
17122 ; line 2: 9600 baud, even parity, 7 bits (VT52 #2)
17123 ; line 5: 9600 baud, even parity, 7 bits (VT52 #3)
13524 ; line 3: 1200 baud, even parity, 7 bits (HP2645)
13525 ; line 4: 1200 baud, even parity, 7 bits (Vadic 1200)
15036 ; line 6: 2400 baud, no parity, 8 bits (HP3000)
17037 ; line 7: 9600 baud, no parity, 8 bits (MC)
>
.endc ; if DZ