• MACRO-20/Longo text programs

    From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.lang.asm on Thu May 14 17:34:34 2026
    From Newsgroup: alt.lang.asm

    I'm working through the "Introduction To DECSYSTEM-20 Assembly
    Programming" book by Stephen Longo. I have the Gorin one as well but the
    Longo text jumps into writing actual programs faster. There's examples
    that the student is supposed to complete at the end of the
    chapters. There's no given sample output and no answers so the student
    is on his own. I thought I'd post some of my solutions if people want to
    follow along on their PDP-10 with the MACRO-20 assembler.

    @exec ch2u5
    LINK: Loading
    [LNKXCT CH2U5 execution]
    Type in an integer: 30
    Sum: 50
    Dif: 10
    @cont
    Type in an integer: 10
    Sum: 30
    Dif: -10


    ; Chapter 2 user exercise 5
    ; Accept an integer from the terminal. Add the integer to
    ; an integer stored in the program and then subtract it
    ; from the same integer. Assume the integer given is 20.
    title ch2u5
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3

    twent: 24 ; The given number 0o24=20 dec
    usrnum: 0 ; Store user's type-in number
    base10: 12 ; 0o12 = 10 decimal base
    ttyin: .priin ; Primary input keyboard
    ttyout: .priou ; Primary output TTY

    msg1: asciz /Type in an integer: / ; Prompt for user data message
    sum: asciz /Sum: / ; Label sum message
    dif: asciz /Dif: / ; Label difference message
    errmsg: asciz /IO Error/ ; Generic error message!

    start: hrroi ac1,msg1 ; Point to prompt message
    psout% ; Print it to TTY

    ; NIN% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Point to keyboard
    move ac3,base10 ; Indicate base 10
    nin% ; Get user integer
    erjmp error ; Handle error
    movem ac2,usrnum ; Save user's num to memory

    ; Do the sum part of the problem now
    hrroi ac1,sum ; Print sum label
    psout% ; To TTY

    ; NOUT% wants device, number, and base in accum 1, 2, 3
    move ac1,ttyout ; Indicate TTY
    move ac2,usrnum ; Get user's number
    add ac2,twent ; Add 20 decimal
    move ac3,base10 ; Indicate base 10
    nout% ; Print sum to TTY
    erjmp error ; Handle error

    movei ac1,15 ; Print a \r
    pbout%
    movei ac1,12 ; Print a \n
    pbout% ; TOPS-20 wants both

    ; Do the difference part of the problem now
    hrroi ac1,dif ; Print diff label
    psout% ; To TTY

    move ac1,ttyout ; Indicate TTY
    move ac2,usrnum ; Retrieve user's num
    sub ac2,twent ; Sub 20 decimal
    move ac3,base10 ; Indicate base 10 dec
    nout% ; Print diff to TTY
    erjmp error ; Handle error
    haltf% ; Done
    jrst start ; Restart prog if desired

    error: hrroi ac1,errmsg ; Indicate error
    psout% ; Print to screen
    haltf% ; Exit
    end start ; That's it
    --
    PGP Key ID: 781C A3E2 C6ED 70A6 B356 7AF5 B510 542E D460 5CAE
    "The Internet should always be the Wild West!"
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.lang.asm on Fri May 15 14:10:41 2026
    From Newsgroup: alt.lang.asm

    Chapter 3, ch3u1 and ch3u2. I find comparisons to be confusing on this
    CPU. On x86, you use "cmp", the flags are set, and you jump based on the outcome. In MACRO-20, you seem to need to test for the thing you don't
    want, and then continue the execution path from there. If the condition
    fires off, it "eats" next instruction, else it goes on. Very odd. See
    the "check:" label below for an example of what I mean.

    @exec ch3u1
    LINK: Loading
    [LNKXCT CH3U1 execution]
    Enter an integer: 6
    6
    @cont
    Enter an integer: -4
    NEG
    @cont
    Enter an integer: 0
    @

    ; Chapter 3 user exercise 1
    ; Accept an integer via NIN% (the text has a mistake here).
    ; If the int is positive, display it
    ; If the int is negative, print "NEG"
    ; Assumed to do nothing if zero.
    ; CAM = compare accumulator to memory location
    ; CAI = compare accum to immediate value
    ; l, g, e, n = less than, greater, equal, not equal suffixes
    title ch3u1
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3

    base: 12 ; 0o12 = 10 decimal
    ttyin: .priin ; Primary input keyboard
    ttyout: .priou ; Primary output to TTY

    prompt: asciz /Enter an integer: / ; User prompt
    negmsg: asciz /NEG / ; Tell user it's negative

    start: hrroi ac1,prompt ; Load user prompt
    psout% ; Print it to TTY

    ; NIN% wants device, radix to 1, 3 and puts results in ac2
    ; Both NIN% and NOUT% require ERJMP, which is like an "else"
    move ac1,ttyin ; Get input from keyboard
    move ac3,base ; Signal what base to get
    nin%
    erjmp done ; Don't worry about error

    ; NIN% will give us an integer, not the ASCII octal for it
    ; Compare against the integer, not the ASCII value
    check: cail ac2,0 ; Is ac2's num less than 0?
    jrst pos ; No/else clause, check +/0

    neg: hrroi ac1,negmsg ; It's negative, load message
    psout% ; and print to TTY
    jumpa done ; This condition is handled

    pos: caig ac2,0 ; Is ac2's num greater than 0?
    jrst done ; Else, it must be 0, goto done

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,ttyout ; Prepare to print positive num
    move ac3,base ; Load desired number base
    nout% ; Output number to TTY
    erjmp done ; Handle error (or not)

    done: haltf% ; Either way we're done
    jrst start ; User can re-run program
    end start ; Tell assember we're done and
    ; also where the prog starts at


    User exercise 2, little caculator (add/sub).

    @exec ch3u2
    LINK: Loading
    [LNKXCT CH3U2 execution]
    Enter an integer: 24
    Enter another integer: 6
    Enter an operation (+ or -): +
    30
    @cont
    Enter an integer: 10
    Enter another integer: 30
    Enter an operation (+ or -): -
    -20
    @cont
    Enter an integer: *
    Error: invalid input or operation
    @

    ; Chapter 3 user exercise 2
    ; Get two integers via NIN%, PBIN% an operation as earlier
    ; in the text (only use + or -). Perform the operation and
    ; output the answer. Give error message if operation is
    ; not + or -.
    title ch3u2
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3
    op=7 ; Save user's operation

    int1: 0 ; User's first num
    int2: 0 ; User's second num

    base: 12 ; 0o12 = 10 decimal
    ttyin: .priin ; Keyboard
    ttyout: .priou ; Primary output to TTY
    add: "+" ; Mathmatical operations
    sub: "-"

    ; User prompts and error messages
    getnum: asciz /Enter an integer: /
    getnm2: asciz /Enter another integer: /
    errmsg: asciz /Error: invalid input or operation/
    opmsg: asciz /Enter an operation (+ or -): /

    start: hrroi ac1,getnum ; Load prompt for int1
    psout% ; And print it

    ; NIN% wants device, radix to 1, 3 and puts results in ac2
    ; Both NIN% and NOUT% require ERJMP, which is like an "else"
    move ac1,ttyin ; Prepare to get from kbd
    move ac3,base ; Requested number base
    nin% ; Fetch number to ac2
    erjmp error ; Handle error
    movem ac2,int1 ; Save user's 1st num

    hrroi ac1,getnm2 ; Load prompt for int2
    psout% ; And print it to TTY

    ; NIN% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Prepare to get from kbd
    move ac3,base ; Requested number base
    nin% ; Fetch number to ac2
    erjmp error ; If error
    movem ac2,int2 ; Save second number

    ; Numbers 1 and 2 are fetched. Now get the operation
    hrroi ac1,opmsg ; Prompt for operation
    psout% ; Print to TTY
    pbin% ; Get char, either + or -
    move op,ac1 ; Save it
    pbin% ; Eat \r else stray input
    pbin% ; Eat \n too

    ; Check the operation is a valid one (+ or - only)
    camn op,add ; Is it '+'?
    jrst plus ; It is equal, do plus
    camn op,sub ; Is it '-'?
    jrst minus ; It is equal, do minus
    jumpa error ; Don't care if otherwise

    plus: move ac2,int1 ; Fetch int1
    add ac2,int2 ; Add int2 to it
    jumpa disp ; Ready to display

    minus: move ac2,int1 ; Fetch int1
    sub ac2,int2 ; Subtract it from int1

    ; Display output section. Print the result that we calculated
    ; above; it is in accumulator 2. We're here by jump or fall-thru.
    disp: move ac1,ttyout ; Output device is TTY
    move ac3,base ; Load base
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    nout% ; Print result, in ac2
    erjmp error ; Handle error
    haltf% ; Else we're finished here
    jrst start ; Re-run/cont the program

    error: hrroi ac1,errmsg ; Load error message
    psout% ; And print to TTY
    haltf% ; Exit to monitor
    end start ; That's it, indicate start
    --
    PGP Key ID: 781C A3E2 C6ED 70A6 B356 7AF5 B510 542E D460 5CAE
    "The Internet should always be the Wild West!"
    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From R.Wieser@address@is.invalid to alt.lang.asm on Fri May 15 21:44:03 2026
    From Newsgroup: alt.lang.asm

    jayjwa,

    In MACRO-20, you seem to need to test for the thing you don't
    want, .... If the condition fires off, it "eats" next instruction,
    else it goes on. Very odd.

    Its not as odd as you might think : imagine the possibly eaten instruction
    is a jump. In that case you jump on "the thing you want".

    Yes, its a bit of a mind-trick to think about it that way. :-)

    You might also think of it as "skip next instruction if true". iow, if the "eaten" instruction is again a jump, the program will take that jump if the comparision is not true.

    Ofcourse, nothing stops you from replacing that jump with the (re)setting of
    a flag in a register. :-)

    Regards,
    Rudy Wieser


    --- Synchronet 3.22a-Linux NewsLink 1.2
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.lang.asm on Sat May 16 14:35:40 2026
    From Newsgroup: alt.lang.asm

    ch3u3
    Lots of comparisons in this one. It still seems backwards.
    @exec ch3u3
    LINK: Loading
    [LNKXCT CH3U3 execution]
    Enter a character (A, B to echo, C to quit): A
    A
    Enter a character (A, B to echo, C to quit): B
    B
    Enter a character (A, B to echo, C to quit): D
    Enter a character (A, B to echo, C to quit): F
    Enter a character (A, B to echo, C to quit): C
    Program complete
    @cont
    Enter a character (A, B to echo, C to quit): *
    Enter a character (A, B to echo, C to quit): C
    Program complete
    @

    Last night I found that DDT can display with your symbols already
    inserted, like this:
    @debug ch3u3
    LINK: Loading
    [LNKDEB DDT execution]
    DDT
    ch3u3$:
    start$b $g
    START/ MOVEI ITER,5

    gdb seems so friendly and luxurious after using DDT. The text doesn't
    warn about dangling newlines (actually \r\n in TOPS-10/20) but your
    program will run incorrectly under EXEC but fine under DDT if you don't
    handle them. The text for TOPS-10 mentions them and of course C
    programmers have been bit by them at some point.

    comment $
    Chapter 3 user exercise 3
    PBIN% a character. PBOUT% the character only if it is A or B.
    Place the above in a loop that terminates after the 5th PBIN%
    or if the letter C is entered.
    $
    title ch3u3
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    iter=7 ; Iterator for loopage

    char: "X" ; User's character

    ; User prompts and messages
    getchr: asciz /Enter a character (A, B to echo, C to quit): /
    compl: asciz /Program complete/

    start: movei iter,5 ; Init iterator for loops
    loop: hrroi ac1,getchr ; Load prompt
    psout% ; And print to TTY

    pbin% ; Get char to ac1
    movem ac1,char ; Save user's char

    ; Input will be char\r\n, deal with \r\n on input stream. Oddly,
    ; the text does not tell you this and your program will run fine
    ; under DDT while debugging but will fail under EXEC.
    pbin%
    pbin%

    ; Now look at what character we have
    move ac1,char
    cain ac1,101 ; Compare to A (0o101)
    jrst disp ; It's A
    cain ac1,102 ; Compare to B
    jrst disp ; It's B
    cain ac1,103 ; Compare to C
    jrst done ; C - exit loop to done
    jumpa pass ; None of these, no output

    disp: pbout% ; Display char in ac1
    movei ac1,15 ; Load \r
    pbout%
    movei ac1,12 ; Load \n
    pbout% ; End in \r\n

    ; Check loop condition. Do we restart the process?
    pass: subi iter,1 ; Cut 1 from our looper
    jumpn iter,loop ; Not zero? repeat loop

    done: hrroi ac1,compl ; Signal program complete
    psout%
    haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; That's it, halt assembler
    --
    PGP Key ID: 781C A3E2 C6ED 70A6 B356 7AF5 B510 542E D460 5CAE
    "The Internet should always be the Wild West!"
    --- Synchronet 3.22a-Linux NewsLink 1.2