mirror of
https://github.com/PDP-10/its.git
synced 2026-04-15 00:09:07 +00:00
262 lines
4.8 KiB
Plaintext
Executable File
262 lines
4.8 KiB
Plaintext
Executable File
;;; -*-midas-*-
|
||
|
||
.sbttl Style macros. Use these if you want
|
||
|
||
;;; ;;; General info:
|
||
;;; ;;; These macros allow one to write STRUCTURED assembler
|
||
;;; ;;; code!! These macros are largely responsible for the
|
||
;;; ;;; amount of time it takes PALX to assemble a system with
|
||
;;; ;;; these macros in use.
|
||
|
||
; 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
|
||
.nlist
|
||
.if p1 ; define symbols only on pass 1
|
||
%.dtmp===.
|
||
.=0
|
||
sect
|
||
.iif nb len, len==.
|
||
.=%.dtmp
|
||
.endc
|
||
.list
|
||
.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. [Some extra double quotes were added to APPEND to do true
|
||
;; appending. Appending a null argument will still not work. -dcp]
|
||
|
||
.macro txtint name
|
||
.nlist
|
||
.macro name op1,op2,op3
|
||
op1'op2
|
||
op3
|
||
.endm name
|
||
.list
|
||
.endm txtint
|
||
|
||
.macro append name,newcft
|
||
.nlist
|
||
name ^|.macro name op1,op2,op3
|
||
op1'|,^|newcft''op2
|
||
op3|,.endm
|
||
.list
|
||
.endm append
|
||
|
||
.macro appnd1 name,line ;append one $line$ (appends newline after $line$)
|
||
append name,^|line
|
||
|
|
||
.endm
|
||
|
||
.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
|
||
; >
|
||
|
||
gncnt=777 ;initialize the if macro
|
||
|
||
.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
|
||
|
||
|
||
; 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 ;init the loop macro
|
||
%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
|
||
|
||
|
||
;;; Allow variables to be declared
|
||
|
||
l%%vars==0 ;length of variable block
|
||
txtint variables
|
||
|
||
.macro .bscalar a
|
||
append variables,<
|
||
a:.blkb 1
|
||
.even
|
||
>
|
||
.endm
|
||
|
||
.macro .wscalar a
|
||
append variables,<
|
||
a:.blkw 1
|
||
>
|
||
.endm
|
||
|
||
.macro .bvector a,b
|
||
append variables,<
|
||
a:.blkb b
|
||
.even
|
||
>
|
||
.endm
|
||
|
||
.macro .wvector a,b
|
||
append variables,<
|
||
.even
|
||
a:.blkw b
|
||
>
|
||
.endm
|
||
|
||
|
||
.macro chk$on start,end
|
||
.wscalar chkval
|
||
chkcom: push (sp),r0,r1,r2
|
||
clr r0
|
||
mov #start,r1
|
||
mov #end,r2
|
||
sub r1,r2
|
||
clc
|
||
ror r2
|
||
loop < add (r1)+,r0
|
||
sorl r2>
|
||
pop r2,r1
|
||
mov r0,4(sp)
|
||
pop r0
|
||
return
|
||
|
||
.macro chkset
|
||
call chkcom
|
||
pop chkval
|
||
.endm
|
||
|
||
.macro chkchk
|
||
call chkcom
|
||
cmp (sp)+,chkval
|
||
if ne,<halt>
|
||
.endm
|
||
.endm
|
||
|
||
.macro chkset
|
||
.endm
|
||
.macro chkchk
|
||
.endm
|