1
0
mirror of https://github.com/PDP-10/its.git synced 2026-03-10 12:48:25 +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

View File

@@ -25,12 +25,12 @@ SRC = syseng sysen1 sysen2 sysen3 sysnet kshack dragon channa \
tensor transl wgd zz graphs lmlib pratt quux scheme gsb ejs mudsys \
draw wl taa tj6 budd sharem ucode rvb kldcp math as imsrc gls demo \
macsym lmcons dmcg hack hibou agb gt40 rug maeda ms kle aap common \
fonts zork 11logo kmp info aplogo bkph bbn
fonts zork 11logo kmp info aplogo bkph bbn pdp11 chsncp
DOC = info _info_ sysdoc sysnet syshst kshack _teco_ emacs emacs1 c kcc \
chprog sail draw wl pc tj6 share _glpr_ _xgpr_ inquir mudman system \
xfont maxout ucode moon acount alan channa fonts games graphs humor \
kldcp libdoc lisp _mail_ midas quux scheme manual wp chess ms macdoc \
aplogo _klfe_
aplogo _klfe_ pdp11 chsncp cbf rug
BIN = sys2 emacs _teco_ lisp liblsp alan inquir sail comlap c decsys \
moon graphs draw datdrw fonts fonts1 fonts2 games macsym maint imlac \
_www_ hqm

View File

@@ -1105,6 +1105,15 @@ expect ":KILL"
respond "*" ":midas sys1; ts gtload_syseng; gtload\r"
expect ":KILL"
# RUG, PDP-11 debugger.
respond "*" ":cwd pdp11\r"
respond "*" ":palx rug\r"
respond "?" "2\r"
respond "?" "100000\r"
respond "?" "1\r"
respond "?" "1\r"
expect ":KILL"
# URUG, GT40 debugger.
respond "*" ":palx sysbin;_sysen2;urug\r"
respond "=YES" "1\r"

12
doc/cbf/rug.featur Normal file
View File

@@ -0,0 +1,12 @@
Rug fixes not mentioned before
1) .TTYTYP -1 means glass TTY
2) "ab and 'a with lower case chars is no longer spuriously
uppercasd
3) $" typeout mode now prints low byte high byte, which allow
strings to come out right and is consistent with the way
typein always was.
To do:
Src Dst opening commands
^P
$X ?

200
doc/cbf/rugord.1 Normal file
View File

@@ -0,0 +1,200 @@
Brief user documentation for Rug.
The order of things in this document is pretty random. Someday
someone should fix it.
Basically Rug expects a symbolic expression followed by a command
which operates on the expression, e.g. "FOO+5=" where "FOO+5" is
the symbolic expression and "=" is the command. Commands may be
one letter (e.g. "="), one letter following an escape (e.g. "$L"
where escape will echo as a dollar sign), or a colon followed by
up to six letters (such as ":HELP").
Symbolic expressions may contain any defined symbol, octal number,
or decimal number (digit-string terminated with a period, e.g.
"143." whereas "143" without the "." would be octal) connected
with the arithmetic operators "+", "-", or space (which is
equivalent to "+" for convenience). $Q (Escape Q) is a special
symbol whose value is the last quantity that rug typed out.
Further, the user can generate ascii or rad50 codes for characters
and use these numbers in any symbolic expression: Typing
single-quote followed by one letter produces the 16-bit quantity
containing the letter in the low byte and zero in the high byte.
Typing double-quote followed by two ascii letters will produce the
16-bit quantity containing the first letter in the low byte and
the second in the high byte. Typing "&" followed by three letters
produces the 16-bit rad50 equivalent of the letters.
If the user types an undefined symbol in an expression, Rug will
beep, generally allowing the user to rubout and correct the
symbol. When the expression is done an error will usually result
(unless the command doesn't care) if there was any undefined
symbol within the expression. There is one exception to the
beep-rule: if the first symbol in the expression is undefined,
then the expression will be terminated immediately, not allowing
the user to correct it.
Many commands will produce different results depending on certain
modes that the user can set. Most modes have "temporary" and
"permanent" settings: temporary modes act until Rug prompts with a
"*". The "*" prompt indicates that all modes have been reset to
their permanent settings.
There are several symbols with predefined values. These are
listed below (note that "user" refers to the user program being
run, e.g. "user R0" means the programs R0):
. Contains the last address opened.
%0 - %7 Standard register definitions (user regs).
.M Mask for searches:
.M has the 16-bit mask.
.M+1 has the 16-bit low address.
.M+2 has the 16-bit hi address.
.STBEG Location containing pointer to bottom (low
address) of symbol table.
.STEND Address of bottom of predefined RUG symbol table.
.START Address of RUG's starting address.
.MXOFF Initially 200. A value must be within this distance
symbol to be printed as that symbol+offset.
ESCAPE COMMANDS (<arg> is symbolic expression):
$Q Value of last quantity typed out
$G Start execution at default start address.
<arg>$G Start execution of user program at <arg>.
<arg>$$G Set default start addr to <arg> and start execution.
<arg>$W Search from low-address (.M+1 contents) to high-address
(.M+2 contents) for <arg> masked by contents of .M.
Each match found will be shown by printing location and
contents. Any type-in by user will stop the search.
<arg>$E Same as W but effective address search. I.e. BR FOO
will match an arg of FOO.
<arg>$B Set a breakpoint at <arg>. (There are 8 breakpoints
available. Use :LISTB to see where breakpoints are
currently set.)
<arg>$P Proceed user program after hitting breakpoint. If no
<arg>, proceed until hitting any breakpoint. If <arg>
then set this breakpoint's count to <arg> and proceed.
If a breakpoint has a count, then it will only break
after being hit count many times.
<arg>$U Remove breakpoint at <arg>. If no <arg> then remove
all breakpoints.
$C Set temporary type-out mode "contants", i.e. type
contents of open locations as octal numbers.
$S Set temp type-out mode "symbols", i.e. type open
location contents as symbols.
$I Set temp type-out mode "instructions", i.e. type
open location contents as instructions.
$R Set temp type-out mode "relative addresses", i.e.
type addresses as symbolic references, INC FOO.
$A Set temp type-out mode "absolute addresses", i.e.
type addresses as octal numbers, INC 14345.
$" Set temp word type-out mode to "ascii", i.e. when
opening words, type out ascii characters.
$' Set byte word type-out mode to "ascii", ie. when
opening words, type out ascii characters.
Note that examining a location in Ascii mode that
contains control characters will cause them to be
shown as the usual ^<char> representation, (or $ for
escape) except that Space, CR, LF and Bell will
actually be sent to the terminal, Tab will cause the
correct number of spaces to be sent,and FF will
clear the screens on displays and CRLF on theirs.
$& Set temp type out mode to radix 50.
ASCII A - Z $ . % 0 - 9
Radix 50 (in octal) 1 - 32 33 34 35 36 - 47
$$C $$S $$I $$R $$A $$" $$' $$&
Like $C $S $I $R $A $" $' and $& but set permanent
type-out modes.
$L Load program. Source loaded from depends on how
this RUG was assembled and environment its running in.
For stand alone disk system, takes block number after
the L.
$Y Dump program. Only meaningful in standalone disk
system thus far. Takes arg of lblock number after
the Y.
$Z Zero all of core. I will change this to $$Z to be less
dangerous soon.
SINGLE-LETTER COMMANDS:
<symbol>: Define <symbol> to be . (i.e. current location).
<arg>= Print value of <arg>.
<arg>><symbol> Define <symbol> to be <arg>, e.g. 1234>FOO defines
FOO to be 1234.
<arg>/ Open location <arg> as word.
<arg>\ Open location <arg> as byte.
<arg><CR> (Carriage-return) Deposit <arg> into current location
if it is open and then close the location and prompt.
No <arg> means no change to current location.
<arg><LF> (Line-feed) Deposit <arg> into current location if
open, then open next location. No <arg> means no
change to current location.
<arg>^ Deposit <arg> and open previous location. No change
if no <arg>.
<arg>] Open location <arg> as symbol.
<arg>[ Open location <arg> as number.
<symbol>$K Half-kill <symbol> so that it won't be used for
printing symbolic addresses.
$$K Kill all symbols in program.
^L Clear screen.
<arg>^N Proceed program in single-step mode: no <arg> means
execute one instruction;q <arg> means execute <arg>
instructions then return to RUG.
_ Type out <arg> in symbolic mode, but don't set
either the temporary or permanent modes.
; Type out <arg> in the last specified temporary
or permanent mode (see $A, $C, $I, $R, $S).
$; Like ; but also set the temporary mode to the
last specified temporary or permanent mode.
$$; Like $; but set permanent mode instead of
temporary mode.
@ Open location addressed by PC in instruction mode
COLON COMMANDS:
:HELP List the colon commands.
:LISTB List all breakpoints set, and their counts.
:EXIT Exists Rug

3
doc/chsncp/-read-.-this- Normal file
View File

@@ -0,0 +1,3 @@
This directory is used for the development of CHAOS Network
NCP software for PDP-11s. Please do not delete any files
from here without consulting with JLK, LSP, or OTA.

4
doc/pdp11/-read-.-this- Normal file
View File

@@ -0,0 +1,4 @@
Don't delete anything out of this directory unless you know what you are doing...
For more information on the programs in this directory, please contact RLL@MC.
-RLL April 13, 1980

View File

@@ -203,6 +203,7 @@
- RIPDEV, replacement for MLDEV for no-longer-existing machines.
- RMAIL, mail reading client.
- RMTDEV, MLDEV for non-ITS hosts.
- RUG, PDP-11 debugger.
- SALV, old file system tool for KA and KL.
- SCAN, TEX output to XGP SCAN file.
- SCANDL, TTY output spy.

203
doc/rug/rug.doc2 Normal file
View File

@@ -0,0 +1,203 @@
.XGP
.double
.fill
Rug is a symbolic debugger which runs on the pdp11.
There are three basic output modes which affect how the
contents of a location get printed.
.nofill
$C causes the location contents to be printed as a number.
$S causes the location to be printed as a symbol.
$I causes the location to be printed as an instruction.
Also there are two minor mode changes:
$A inhibits the printing of symbols (like in an instruction).
$R reverses the action of $A.
.fill
By typing two alt modes, the mode gets more permanently changed,
but can be changed back, of course by switching to a different mode.
To open a location type / or \.
This opens it in word or byte mode respectively.
However if an odd location is opened, it will be in byte
mode even if / was typed.
After a location is opened, a number can be placed into it numerically,
symbolically, or as an instruction. For instance if FOO is defined,all of the following are legal:
.nofill
100/ 53 MOV @FOO+.(%2),(%3)+
100/ 53 FOO+352-10
100/ 53 6
.fill
To open a register, type %5/ and %5 will be opened as expected
(or if it is a defined symbol
just type its name)
When typing an instruction, type
the operation code followed by a space or tab.
Extra tabs and spaces are ignored here.
Then type the next field. Follow it by a comma if
there is another field. Then type the other field.
When inputting a symbol, the arithmetic operations
are +, -, *, and ! for add, subtract multiply
and divide respectively.
Important note: when typing in
condition codes, type SE CZ, for example. in other words, type
SE(space) or CL(space), depending on whether you
wish to clear or set the flags, then follow it with all the
flags you wish to modify by the instruction.
After a location is opened, carriage return will close it, placing
in it any value that might have been typed directly before the return,
unless some operations were performed, in which case it will not change
the contents.
Line feed will open the next word or byte, depending
on whether the previous location were opened in word or byte mode.
if the previous location were opened in instruction mode, line feed
will open the next instruction. (it will skip over to the end of
a multiple lenth instruction.
^ will go to either one word or one byte ahead of the opened location.
being in instuction mode does not change this.
/ opens the last memory location mentioned
(like JMP FOO,MOV BAR,FOO or TSTB @FOO all open FOO)
_ opens second last memory location mentioned
(MOV BAR,FOO opens BAR with an extra slash)
tab (contrl i) opens the location which is the
value of the number in the location opened.
< will return to the sequence interrupted by extra tabs
.center
breakpoints
To set a breakpoint, type FOO$B
This sets a breakpoint at location FOO.
To delete a breakpoint, type FOO$D.
To delete all breakpoints, type $D.
To see which locations have breakpoints in them,
type .B/. This will contain either a random location within rug,
indicating that that breakpoint is not set, or a location which
would be where that breakpoint is.
If line feed is typed, you can see where B1 is.
If another line feed is typed, you can see where B2 is, etc.
up to B7. Or type .B+6 to examine breakpoint 6.
To examine the count number of each
breakpoint, type .C+n/ to examine the count of breakpoint n.
(The count is how many times you are to proceed through that
breakpoint before stopping.)
.center
running the program
.nofill
FOO$G starts it at location FOO
$P lets it proceed from where it left off
n$P causes it to stop after looping through the last breakpoint
n times.
.fill
The breakpoint repeat counts can be inpected and modified
by opening .B and typing 9 line feeds.
The repeat count for breakpoint 0 will then be typed.
The repeat counts for breakpoints 1 through 7 follow in sequence.
.center
single step mode
by typing ^N, you can execute one more instruction.
Rug will type SS;adr, where adr is the address of the
next instruction to be executed.
To execute 5 instructions, type 5^N, etc.
Breakpoints are disabled in single instruction mode.
By typing 400^N, it is very likely you might skip a few
breakpoints.
.S is a defined symbol which is the user status.
.P is a defined symbol which is the user priority
.center
defining symbols
To define a symbol, type 100,FOO:
This defines FOO as location 100.
It is perfectly legal to redefine symbols.
All radix 50 chars are legal in a symbol.
Symbol names longer than 6 characters get automatically chopped.
Also, FOO: defines FOO as . (address of the open
location)
To half kill an already defined symbol type FOO^k.
To unhalf kill a symbol you accidentally half killed, just
redefine it (type FOO,FOO)
A string of numbers will be considered
as octal unless there is a decimal point somewhere in it
or it contains an 8 or 9.
.break
& causes radix 50 to be input (&abc is like typing the numeric
quantity which is abc in radix 50 packed with a on the left)
spaces are zero radix 50
.break
[ will type the two ascii bytes in the opened word
.break
.break
] performs a radix 50 mode unpack of the opened word.
.break
' causes the ascii value of the next character to be input
(mov ##'F,R2 is legal)
.break
" causes the next two char.'s ascii value to be packed into a word
.center
loading a file
To load a file from the paper tape reader,
type $LP:. If it is on multiple tapes, the debugger
halts at the end of each tape and hitting "continue"
causes the next tape to be read.
Use RADIA;PUNCH BIN on the PDP10 to punch out a
debugger-loadable tape, which is an absolute loader
binary of the program which gets loaded directly onto
disk, followed by an absolute loader tape of the
symbol table which gets loaded directly into core.
To load a file from the PDP10's disk, type $LT: <user;file name>,
where <user;file name> is the ITS file specification for the file to be
loaded.When it is done loading you'll be back
in the debugger.
To load a program without first zeroing
core, type $^L instead of $L.
Symbols are always loaded with the program.
To save the debugger on disk type $^D. To get it back type $^U.
To load a program of disk #<n>, type $L<n>:<file name>. To save it (dump it)
type $Y<n>:<file name>. If a file with the name <file name> exists already,
rug will type FILE EXISTS DELETE?. If you then type Y, rug will delete the old
file, and dump core into a new file with <file name>. If you type anything else,
the file is not dumped.
.center
zeroing core and initializing the symbol table.
To zero all of core and initialize the symbol table, type $$Z. To just
reinitialize the symbol table, type $Z.
.center
interacting with programs
Programs should leave locations 157000-160000 alone.
That is the resident portion of rug.
If a program is running and you wish to get to the debugger,
halt the program and start at location 157000.
Rug should swap the program out and itself in.
Proceed is disabled when the debugger is
started with the switches as opposed to trapping there.
(the program executes "3")
Aside from the the 300 locations already mentioned, the program
can use all 28k of core.
However, currently only up to 157500 (the
absolute loader) is swapped in and out.
Maximum symbol table size is about 2000 symbols
(logo is well under the limit.)
To find out how much symbol table room is used,
type "..B="
The mimumum allowed value of ..B is 10000.

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