• 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
  • From jayjwa@jayjwa@atr2.ath.cx.invalid to alt.lang.asm on Mon May 18 22:40:18 2026
    From Newsgroup: alt.lang.asm

    Two this time, ch3u4 and ch3u5.

    Enter two integers and display the greater.
    @exec ch3u4
    LINK: Loading
    [LNKXCT CH3U4 execution]
    Enter integer number one: -5
    Enter number two: 0
    0 is the greater number.
    @cont
    Enter integer number one: 10
    Enter number two: 20
    20 is the greater number.
    @

    comment $
    Chapter 3 user exercise 4
    Input two integers via NIN%. Output the greater via NOUT%. The
    program should be restartable. The text does not say what to
    do if they are the same so we'll assume they must be different.
    $
    title ch3u4
    search monsym ; Use monitor symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3
    num1=6 ; Use higher accum for nums
    num2=7 ; instead of mem locations

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

    ; User prompts and error messages
    entnm1: asciz /Enter integer number one: /
    entnm2: asciz /Enter number two: /
    errmsg: asciz /Error./ ; Very generic
    isgtr: asciz / is the greater number./

    start: hrroi ac1,entnm1 ; Load user prompt
    psout% ; Output to TTY

    ; Get first integer from user
    move ac1,ttyin ; Point to kbd
    move ac3,base ; Load base
    ; NIN% wants device, radix to 1, 3 and puts results in ac2
    nin% ; Get integer
    erjmp error ; Handle error
    move num1,ac2 ; Save integer 1

    ; Get second integer from user
    hrroi ac1,entnm2 ; Load num #2 prompt
    psout% ; Output to TTY

    move ac1,ttyin ; Point to keyboard
    move ac3,base ; Load base
    nin% ; Get integer #2
    erjmp error ; Handle error
    move num2,ac2 ; Save integer 2

    ; Compare integer 1 to integer 2. Save num1 to ac3 before it
    ; gets over written and then put it back
    move ac3,num1 ; Remember num1 because...
    sub num1,num2 ; Cut num2 out of num1
    jumpl num1,gtr2 ; Negative? num2 > num1
    jumpg num1,gtr1 ; Positive? num1 > num2
    jumpa done ; Neither (num1=num2)

    gtr2: move ac2,num2 ; Load num2 for NOUT%
    jumpa disp ; Display it

    gtr1: move ac2,ac3 ; Fetch num1 saved from above

    disp: move ac1,ttyout ; Point to TTY
    move ac3,base ; Indicate base
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    nout% ; ac2 already loaded
    erjmp error ; Handle error else print
    hrroi ac1,isgtr ; Load "greater" message
    psout% ; Print to TTY

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program

    error: hrroi ac1,errmsg ; Load error message
    psout% ; Print
    haltf% ; Exit to monitor
    end start ; That's it


    Enter 5 integers and note the position of the greatest.

    These comparisons still don't make any sense but I can just run them
    with DDT and flip them to the condition I don't want so I get the
    condition that I don't didn't want.

    @exec ch3u5
    LINK: Loading
    [LNKXCT CH3U5 execution]
    Enter number 1:10
    Enter number 2:20
    Enter number 3:2
    Enter number 4:15
    Enter number 5:8
    The largest integer is at position 2
    @cont
    Enter number 1:10
    Enter number 2:20
    Enter number 3:50
    Enter number 4:34
    Enter number 5:60
    The largest integer is at position 5
    @

    comment $
    Chapter 3 user exercise 5
    Set up a loop, accept five integers. Use NOUT% to display the
    position of the largest integer after they have been entered.
    $

    title ch3u5
    search monsym ; Use monitor symbols

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    gtrpos=4 ; Position of greatest int
    num=5 ; Number being looked at
    pos=6 ; Position of entry
    iter=7 ; Iterator for loopage

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

    ; User prompts and messages
    etrmsg: asciz /Enter number /
    errmsg: asciz /IO error/ ; Generic error message
    lrgmsg: asciz /The largest integer is at position /

    start: xor num,num ; Zero out number
    movei pos,1 ; and init position to first
    movei iter,5 ; Do 5 loops, init looper

    getnum: hrroi ac1,etrmsg ; Load get number prompt
    psout% ; And print

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,ttyout ; Print to TTY position num
    move ac3,base ; Load base
    move ac2,pos ; The numerical position
    nout% ; And print it
    erjmp error ; Handle error
    movei ac1,72 ; To print ":"
    pbout% ; To TTY

    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Point to keyboard
    move ac3,base ; Load base
    nin% ; Get integer to ac2
    erjmp error ; Handle error

    ; Examine number we just got that's in ac2. We have to test for the
    ; case we *do not* want, because the opcodes are backward (???)
    caml num,ac2 ; Is it > what we have?
    jrst lesser ; No, jump

    move num,ac2 ; This is greater, note it
    move gtrpos,pos ; And its position

    lesser: addi pos,1 ; Go to next position
    subi iter,1 ; Decrement loop counter
    jumpn iter,getnum ; Not 0? Get next number

    ; By now we've the position of the greatest integer. Display it
    disp: hrroi ac1,lrgmsg ; Load "largest" message
    psout% ; Print to TTY
    move ac1,ttyout ; Print to TTY position num
    move ac3,base ; Load base
    move ac2,gtrpos ; Pos of greatest integer
    nout% ; And print it
    erjmp error ; Handle error

    haltf% ; Exit to monitor
    jrst start ; Restartable program

    error: hrroi ac1,errmsg ; Print error message
    psout% ; To TTY
    haltf% ; Exit to monitor level
    end start ; That's it


    One more user exercise in chapter 3 and I'm on to chapter 4.
    --
    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 Tue May 19 22:55:48 2026
    From Newsgroup: alt.lang.asm

    ch3u6

    Check positive integers for even/odd without using division.
    @exec ch3u6
    MACRO: ch3u6
    LINK: Loading
    [LNKXCT CH3U6 execution]
    Enter a positive integer to check for even or odd: 0
    @cont
    Enter a positive integer to check for even or odd: 3
    The number is odd.
    @cont
    Enter a positive integer to check for even or odd: 120
    The number is even.
    @cont
    Enter a positive integer to check for even or odd: 121
    The number is odd.
    @

    comment $
    Chapter 3 user exercise 6
    Accept an integer via NIN%. Considering only positive integers,
    PSOUT% a phrase stating whether the integer is EVEN or ODD.
    Use repeated subtractions of 2 to achieve this.
    $
    title ch3u6
    search monsym ; Use monitor's symbols

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    num=4 ; The user's integer

    base: 12 ; 10 decimal
    ttyin: .priin ; Keyboard is primary input
    ttyout: .priout ; Output to TTY

    ; User promps and messages
    etrmsg: asciz /Enter a positive integer to check for even or odd: /
    numeve: asciz /The number is even./
    numodd: asciz /The number is odd./
    errmsg: asciz /Error invalid input./

    start: hrroi ac1,etrmsg ; Load get num prompt
    psout% ; Print to TTY

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

    ; The text says "consider only positive integers" but having
    ; the program return "odd" for zero just seems wrong so error
    ; check that the number is actually positive before we act
    jumple num,done ; Exit early if <= 0

    ; Keep subtracting 2 from the user's number. If we hit zero, it
    ; is even, if we go below zero, it is odd. Keep looping if it's
    ; greater than zero until one of the above conditions occurs.
    loop: subi num,2 ; Cut 2 from number
    jumpg num,loop ; It's still greater than 0
    jumpl num,odd ; It's negative, thus odd

    even: hrroi ac1,numeve ; Fall-thru, num even
    psout% ; Print to TTY
    jumpa done ; Already indicated "even"

    odd: hrroi ac1,numodd ; Load "odd" message
    psout% ; Print to TTY

    done: haltf% ; Exit to monitor level
    jrst start ; Program is restartable

    error: hrroi ac1,errmsg ; Load error prompt
    psout% ; And print to TTY
    haltf% ; Exit program to monitor
    end start ; Tell assembler it's done
    --
    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 22 18:38:07 2026
    From Newsgroup: alt.lang.asm

    ch4u3 and ch4u4. Exercises 1 and 2 didn't really require
    programming. This chapter deals with "arrays", indexing, and address
    modes. 1 of the modes seems pretty exotic, two simple, and 1 I can use
    if I think about it.

    @exec ch4u3
    LINK: Loading
    [LNKXCT CH4U3 execution]
    10 plus 20 using direct addressing: 30
    10+20 using immediate addressing: 30
    10+20 using indirect addressing: 30
    The sum of 10 and 20 using index addressing: 30
    @

    comment $
    Chapter 4 user exercise 3
    Write a program that will add the same two integers four times
    using a different addressing move for each time.
    Exercise 1 does not require a program, but is actually answered
    by doing this exercise and exercise #2 is a flow char that's
    already drawn in the text.
    $
    title ch4u3
    search monsym ; Use monitor's symbols

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

    list: num1 ; Label location of first num
    num1: 12 ; 10 decimal
    num2: 24 ; 20 decimal

    base: 12 ; 10 decimal
    ttyin: .priin ; Keyboard is primary input
    ttyout: .priout ; Output to TTY

    ; Prompts and user messages. Most of these have embedded \r\n
    dirmsg: asciz /10 plus 20 using direct addressing: /
    immmsg: asciz /
    10+20 using immediate addressing: /
    indmsg: asciz /
    10+20 using indirect addressing: /
    idxmsg: asciz /
    The sum of 10 and 20 using index addressing: /

    start: hrroi ac1,dirmsg ; Load direct prompt
    psout% ; Print to TTY
    move ac2,num1 ; Direct to ac2
    add ac2,num2 ; Add num2 to ac2
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,ttyout ; Indicate dest is TTY
    move ac3,base ; Indicate base
    nout% ; Print to TTY
    erjmp error ; Handle error

    hrroi ac1,immmsg ; Load immediate message
    psout%
    movei ac2,12 ; Immediate 10 to ac2
    addi ac2,24 ; Add 20 immed to ac2
    move ac1,ttyout ; Indicate dest is TTY
    move ac3,base ; Indicate base
    nout% ; Print sum to TTY
    erjmp error ; Handle error

    hrroi ac1,indmsg ; Load "indirect" message
    psout% ; Print to TTY
    movei ac2,@list+1 ; Load 10 decimal
    addi ac2,@list+2 ; Add next decimal number
    move ac1,ttyout ; Point to TTY for output
    move ac3,base ; Indicate base 10
    nout% ; Print sum TTY
    erjmp error ; Just exit on error

    hrroi ac1,idxmsg ; Load "index" message
    psout% ; And print it
    movei ac3,1 ; Set up index (1) to ac3
    move ac2,list(ac3) ; Move list+1
    addi ac3,1 ; Set index (2) now
    add ac2,list(ac3) ; Add to sum list+2
    move ac1,ttyout ; Ready to print to TTY
    move ac3,base ; Put back base (overwrote it)
    nout% ; Number was alread in ac2
    erjmp error ; Handle error (or not)

    error: haltf% ; Error or not, done
    jrst start ; Restartable program
    end start ; Assembler's work is done



    This next one is basically a FOR loop.

    @exec ch4u4
    LINK: Loading
    [LNKXCT CH4U4 execution]
    The sum is 15
    @

    comment $
    Chapter 4 user exercise 4
    Code the following high-level language notation into assembly
    language:

    FOR I = I TO 3
    SUM = SUM + A(I)
    NEXT I
    PRINT SUM

    Assume the array A contains 4, 2, 9.
    $
    title ch4u4
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    sum=2 ; Tally array sum here
    ac3=3
    iter=4 ; Iterator for loopage

    base: 12 ; 10 decimal
    ttyin: .priin ; Keyboard is primary input
    ttyout: .priout ; Output to TTY
    A: exp 4, 2, 9 ; Our array/list, idx 0-2

    start: xor sum,sum ; Clear sum
    xor iter,iter ; Init iter, loop 0-2
    loop: add sum,A(iter) ; Add element at A(iter)
    addi iter,1 ; Increment loop counter
    caie iter,3 ; Did we do ALL list yet?
    jrst loop ; No, re-loop

    ; If we're here it's time to print the total sum. hrroi can
    ; take a message string directly like so:
    hrroi ac1,[ asciz /The sum is /]
    psout% ; And print

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,ttyout ; Indicate TTY is dest
    move ac3,base ; Indicate base 10 dec
    nout% ; sum should still be in ac2
    erjmp done ; Handle error (or not)

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; Tell assembler it's done


    Something odd happens with DDT: I label the accumulators, but there's no distinction between the accumulator's label that I gave it and a
    plain-jane value that occurs. DDT does not differentiate. For example,
    above in the "loop:" area, I compare to *values* but the debugger labels
    those values with what I assigned to accumulators, like this:

    LOOP+1/ ADDI ITER,AC1 $x
    ITER/ SUM AC1
    LOOP+2/ CAIE ITER,AC3

    This is the code that made that:
    addi iter,1
    caie iter,3

    In other words, in the above example, DDT should have left the "1" and
    the "3" as is, as the values they are. I'm not sure if this can be
    fixed, or how. Had I an instructor I'd certainly ask him because, in
    that context, I'm refering to numerical values and not accumulators.
    --
    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 Tue May 26 20:46:12 2026
    From Newsgroup: alt.lang.asm

    ch4u5

    I must remember to use an accumulator for indexing, else I would
    scribble into some other memory. I'm guessing there's no equal of a
    "segfault" on PDP-10? Once I overwrote part of premsg but the program
    still ran. On MS-DOS you could scribble all over, too.

    Reverse parts of an array, and I'm onto chapter 5. In the previous
    example, I wrote array A: as 4, 2, 9. Of course there's no "9" in octal
    but the assembler assumed it was decimal and the program ran anyway. It
    should be as below in this example.

    @exec ch4u5
    LINK: Loading
    [LNKXCT CH4U5 execution]
    The array before swapping: 429
    The array after swapping: 492

    comment $
    Chapter 4 user exercise 5
    Write a program that will interchange the second and
    third elements in the array 4, 2, 9 (decimal) and print
    the new array. The program should operate as this high-level
    example:

    DUMMY = A(I)
    A(I) = A(I + 1)
    A(I + 1) = DUMMY
    $
    title ch4u5
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3
    iter=4 ; Iterator for looping loopage
    tmp=5 ; Temp swap space
    idx=6 ; Indexer

    base: 12 ; 10 decimal
    ttyout: .priout ; Primary output to TTY
    A: exp 4, 2, 11 ; Array in octal (4,2,9)

    ; User messages and carriage-return
    premsg: asciz /The array before swapping: /
    posmsg: asciz /The array after swapping: /
    cr: asciz /
    /

    start: hrroi ac1,premsg ; Load pre-swapping message
    psout% ; And print it

    ; Print the array as-is. This will be without commas or spaces
    ; but that's fine for an example execise. Note indexers MUST
    ; be IN accumulators.

    xor iter,iter ; Clear iterator
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    loop1: move ac1,ttyout ; Indicate dest is TTY
    move ac2,A(iter) ; Load number from array A
    move ac3,base ; Indicate base
    nout% ; Print it
    erjmp error ; Handle error

    addi iter,1 ; Increment loop counter
    caie iter,3 ; Time to stop or not?
    jrst loop1 ; No it is not

    hrroi ac1,cr ; Print a \r\n
    psout%

    ; Swap the array elements by moving the contents of the memory to
    ; a temp accumulator and then moving that into its new spot in A()
    ; The second element is index 1 and the third is index 2. No other
    ; elements need swapping according to the directions. Indexers for
    ; MOVEM MUST be IN accumulators. Using 1, 2, etc directly does not work.
    swap: movei tmp,@A+1 ; Load 2nd element to tmp location
    movei ac1,@A+2 ; Load 3rd element to temp location
    movei idx,1 ; Indicate we want index pos 1
    movem ac1,A(idx) ; Overwrite 2nd element with 3rd
    movei idx,2 ; Indeicate we want index pos 2
    movem tmp,A(idx) ; Overwrite 3rd element with 2nd

    ; Print out revised array
    hrroi ac1,posmsg ; Load "post" message
    psout% ; Print to TTY

    xor iter,iter ; Clear iterator
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    loop2: move ac1,ttyout ; Indicate dest is TTY
    move ac2,A(iter) ; Load number from array A
    move ac3,base ; Indicate base
    nout% ; Print it
    erjmp error ; Handle error

    addi iter,1 ; Increment loop counter
    caie iter,3 ; Time to stop or not?
    jrst loop2 ; No it is not

    hrroi ac1,cr ; Print a \r\n
    psout% ; To TTY because we're done
    haltf% ; Done
    jrst start ; Restartable program

    error: haltf% ; Some error occured
    end start ; Tell assembler we're done
    --
    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 Thu Jun 4 16:43:35 2026
    From Newsgroup: alt.lang.asm

    ch5u6

    Make a table with A..Z and hex equal.

    There's a small error in the text, explained below. This is the end of
    chapter 5.

    @exec ch5u6
    LINK: Loading
    [LNKXCT CH5U6 execution]
    A 41
    B 42
    C 43
    ...
    X 58
    Y 59
    Z 5A
    @

    comment $
    Write a table to that will make an ASCII table of capital letters
    and their hexadecimal values, A..Z. The text has an error in that
    it labels A..Z as 0x41..0x7A when really it is 0x41..0x5A. 'z'
    (lower case) is 0x7A, not 'Z' (capital letter).
    $
    title ch5u6
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators
    ac2=2
    ac3=3
    iter=4 ; Loop iterator for loopage

    base: 20 ; Base 16 in octal
    ttyout: .priout ; Output to TTY
    tab: 11 ; ASCII tab char in octal
    cr: asciz /
    / ; \r and \n together

    start: movei iter,"A" ; Init to "A". Need double quotes. prtchr: move ac1,iter ; Read to print via PBOUT%
    pbout% ; Send character
    move ac1,tab ; Read to send \t
    pbout% ; Send character

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,ttyout ; Point to TTY
    move ac2,iter ; Load num for printing hex
    move ac3,base ; Base hexadecimal
    nout% ; Print character in hex
    erjmp done ; Error? Just exit.

    hrroi ac1,cr ; Print \r\n after one complete line
    psout% ; Ready for next line

    cail iter,"Z" ; Is it still less than "Z"?
    jrst done ; Yes, "eat" done. Did I mention
    ; how asinine PDP-10 compares are?
    addi iter,1 ; Increment character
    jumpa prtchr ; Do printing loop again

    done: haltf% ; End program
    jrst start ; Restartable program
    end start ; Tell assembler we're done
    --
    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 Jun 12 17:14:45 2026
    From Newsgroup: alt.lang.asm

    Disregarding appendices, Chapter 6 is almost 40% of the book. Why they
    packed so much into this chapter I don't know; going will be slow. On
    top of that there's a dozen or so new opcodes and it's all those logic/shift/rotate/bit commands that make you wonder why you started
    into assembly in the first place.

    ch6u1 - make alphabet chars lowercase
    ch6u2 - make alphabet chars uppercase (as modified)

    There's an issue with ch6u2 because, while it looks like the mirror of
    ch6u1, it specifies bit 29 while likely they meant bit 30. My solution
    has both. This wouldn't be the first time there was a discrepancy in the
    text versus the example code.

    @exec ch6u1
    LINK: Loading
    [LNKXCT CH6U1 execution]
    Enter a single character: a
    a
    @cont
    Enter a single character: B
    b
    @cont
    Enter a single character: 6
    6

    @exec ch6u2
    LINK: Loading
    [LNKXCT CH6U2 execution]
    Enter a single character: A
    A
    @cont
    Enter a single character: b
    B
    @cont
    Enter a single character: 8
    ruA
    @cont
    Enter a single character: 3

    comment $
    PBIN% a character, set bit 30 and print it via PBOUT% What
    happens when you PBIN% a capital letter? A digit?
    $
    title ch6u1
    search monsym

    ac1=1 ; Label used accumulators

    bitmsk: ^B100000 ; Mask to set bit 30, equal 32 decimal
    getmsg: asciz /Enter a single character: / ; User prompt message

    start: hrroi ac1,getmsg ; Load user prompt message
    psout% ; Print to TTY
    pbin% ; Get the character
    ior ac1,bitmsk ; Set bit in bitmsk
    pbout% ; Print it
    pbin% ; Eat \r
    pbin% ; Eat \n
    haltf% ; Exit to monitor
    jrst start ; Restart program
    end start ; Tell assembler that's all



    comment $
    Write a program that will PBIN%. After the character is accepted,
    clear bit 29 and PBOUT% the result. What happens when you PBIN%
    a capital letter? A digit?

    Note the text says "bit 29" but, following the previous exercise,
    it might actually mean "bit 30". Clearing bit 29 shifts on the
    ASCII table, but clearing bit 30 does the opposite of the previous
    exercise (but does not output ASCII numbers). Here I assume it
    wants "clear bit 30" since it makes more sense to mirror exercise
    ch6u1.
    $
    title ch6u2
    search monsym

    ac1=1 ; Label accumulators used

    getmsg: asciz /Enter a single character: / ; User input prompt
    mask1: ^B0100000 ; Mask for bit 30 set
    mask2: ^B1000000 ; Mask for bit 29 set

    start: hrroi ac1,getmsg ; Prompt user for character
    psout% ; Print to TTY
    pbin% ; Get char from keyboard
    ; Use 'mask1' for how I think the text meant the exercise, or 'mask2'
    ; for how the text is written verbatum.
    andcm ac1,mask1 ; Clear bit according to mask
    pbout% ; Print new value
    pbin% ; Eat dangling \r
    pbin% ; and also \n
    haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; End assembly
    --
    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 Mon Jun 15 15:44:47 2026
    From Newsgroup: alt.lang.asm

    ch6u3
    This one took some thinking. Examine each bit in a user-entered integer
    and print HIGH or LOW for each. My solution prints the original digit as
    binary and then each number after (so that I could verify that it
    worked). I examine the integer from the LSB side. The exercise does not
    specify which direction to go in. Rigth-to-left was easiest.

    @exec ch6u3
    LINK: Loading
    [LNKXCT CH6U3 execution]
    Enter a decimal integer to examine: 54
    110110
    LOW
    11011
    HIGH
    1101
    HIGH
    110
    LOW
    11
    HIGH
    1
    HIGH
    @cont
    Enter a decimal integer to examine: 2
    10
    LOW
    1
    HIGH
    @cont
    Enter a decimal integer to examine: 0
    0
    LOW

    comment $
    Accept an integer in base 10. Examine each bit. If set, print the
    word HIGH, followed by a CR. If not set, print LOW and a carriage
    return (example of parallel-to-serial conversion).
    $
    title ch6u3
    search monsym ; Use monitor's symbols

    ac1=1 ; Label accumulators used
    ac2=2
    ac3=3
    ac4=4

    ttyin: .priin ; Primary input is keyboard
    ttyout: .priout ; Primary output to TTY
    base: 12 ; Input base, 10 decimal
    mask: ^B1 ; Compare with LSB for HIGH

    getmsg: asciz /Enter a decimal integer to examine: / ; User prompt
    himsg: asciz /HIGH
    /
    lomsg: asciz /LOW
    / ; Announce high or low for bits msg

    start: hrroi ac1,getmsg ; Load prompt for getting integer
    psout% ; Print to TTY

    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Indicate keyboard is input
    move ac3,base ; Request base 10 decimal
    nin% ; Get number
    erjmp done ; Can't continue if no number

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    strip: move ac1,ttyout ; Print to TTY
    movei ac3,2 ; Indicate binary base
    nout% ; Output number
    erjmp done ; Just exit on error
    movei ac1,15 ; Print \r\n
    pbout%
    movei ac1,12
    pbout%
    move ac4,ac2 ; Don't clobber ac2 - we need it
    and ac4,mask ; Test current LSB
    skipe ac4 ; Is it zero?
    jrst high ; No, it's one

    low: hrroi ac1,lomsg ; Load "low" message
    psout% ; Print to TTY
    jumpa next ; One message per condition

    high: hrroi ac1,himsg ; Load "high" message
    psout% ; Print it; fall-thru to next LSB

    next: lsh ac2,-1 ; Logical shift right 1: look at LSB
    jumpn ac2,strip ; Num not zero yet? Strip more bits

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; Assembly has concluded
    --
    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 Tue Jun 16 20:56:37 2026
    From Newsgroup: alt.lang.asm

    ch6u4

    More bit testing programs. The text didn't mention IDIVI but I knew it
    from the TOPS-10 assembly boot. Thankfully I didn't have to use
    subtraction to do division/mod. Still no way mentioned to clear the
    input buffer. There's got to be a better way than calling PBIN% twice.

    Input a character, count bits, and set parity (see comment below at top
    of program). I'm going to try out the FAIL assember next. So far this
    has been MACRO-20.

    @exec ch6u4
    LINK: Loading
    [LNKXCT CH6U4 execution]
    Enter a character to check for parity: a
    1100001
    Number of bits set: 3
    Odd, setting bit 28
    11100001
    @cont
    Enter a character to check for parity: c
    1100011
    Number of bits set: 4
    Even, clearing bit 28
    1100011
    @cont
    Enter a character to check for parity: #
    100011
    Number of bits set: 3
    Odd, setting bit 28
    10100011
    @

    There's no answer key, but that looks correct because '#' = 35 ASCII
    decimal which is

    Python 3.12.13 (main, Mar 3 2026, 15:06:31) [GCC 15.2.0] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    print( bin( 35 ) )
    0b100011


    comment $
    PBIN% a character. Count the number of bits set in the word. If the number
    of bits is odd, set bit 28. If the number is even, clear 28. This program illustrates even parity - the parity bit is available for checking errors
    when transferring information over phone lines.
    $
    title ch6u4
    search monsym

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    ac4=4 ; Keep track of each bit to test
    count=5 ; Track number of set bits
    rem=6 ; Remainder for division

    ttyout: .priout ; Primary output to TTY
    getnum: asciz /Enter a character to check for parity: /
    bitset: asciz /Number of bits set: / ; User prompts and messages
    crlf: 15B6+12B13 ; Bit-pack a \r\n
    b28msk: ^B10000000 ; Bit 28 mask
    tstmsk: ^B1 ; Test a bit mask
    char: block 1 ; Save input char for prg end
    base10: 12 ; 10 in decimal - display base
    base2: 2 ; Base to display char in so
    ; so we can verify which bits set
    subttl input

    start: hrroi ac1,getnum ; Load user prompt message
    psout% ; Print to TTY
    pbin% ; Get character to ac1
    movem ac1,char ; And save for later

    subttl calculate

    setz count, ; Clear count (total)
    more: move ac4,ac1 ; Don't clobber ac1 - we need it
    and ac4,tstmsk ; Test current LSB
    skipe ac4 ; Is it zero?
    addi count,1 ; No, count it in total

    lsh ac1,-1 ; Look at next LSB
    jumpn ac1,more ; More bits to look at?

    subttl output

    ; By now, we have total number of set bits in 'count' and the
    ; original character saved to 'char'.
    pbin% ; Clear input buffer. Eat \r
    pbin% ; and \n

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac2,char ; Reload original character
    move ac1,ttyout ; Point to TTY device
    move ac3,base2 ; Indicate binary display
    nout% ; Output original char as bits
    erjmp done ; Handle error

    hrroi ac1,crlf ; Emit newline
    psout%
    hrroi ac1,bitset ; Load "bits set" message
    psout% ; Print to TTY

    move ac1,ttyout ; Print to TTY the
    move ac2,count ; number of bits that are set
    move ac3,base10 ; Print number in decimal
    nout% ; Output to TTY
    erjmp done ; Done either way
    hrroi ac1,crlf ; Emit newline
    psout%

    ; Now we look at 'count' and see if it's even or odd. Use mod for this.
    div: idivi count,2 ; Divide 2 and check remainder
    jumpe rem,even ; No remainder? It's even

    odd: hrroi ac1,[asciz /Odd, setting bit 28
    /] ; Else it's odd
    psout% ; Print to TTY
    move ac1,char ; Fetch original character
    ior ac1,b28msk ; At odd, set bit 28
    jumpa endmsk ; Skip "even" code block

    even: hrroi ac1,[asciz /Even, clearing bit 28
    /] ; Note even bit number
    psout%
    move ac1,char ; Fetch orginal character
    andcm ac1,b28msk ; At even, clear bit 28

    endmsk: move ac2,ac1 ; Display final bits to show
    move ac1,ttyout ; the results of masking
    move ac3,base2 ; As bits
    nout% ; Output to TTY
    erjmp done ; Handle error (or not)

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; Assembly is finished
    --
    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 Wed Jun 17 18:00:00 2026
    From Newsgroup: alt.lang.asm

    ch6u5.fai

    This is the FAIL assembler. It seems to be a drop-in replacement - at
    least for the programming that I'm doing. This program requires to check
    a user-input number, look at bit 30, then output bits 30-35 on a special condition (see comment section).

    @exec ch6u5
    <PROGRAMMING>CH6U5.FAI.6
    FAIL: ch6u5
    LINK: Loading
    [LNKXCT CH6U5 execution]
    Enter a number to check bits 30-35: 1230
    Your number in bits is 10011001110
    @cont
    Enter a number to check bits 30-35: 1454
    Your number in bits is 10110101110
    30-bit is set
    New number in octal: 56
    @cont
    Enter a number to check bits 30-35: 1455
    Your number in bits is 10110101111
    30-bit is set
    New number in octal: 57

    comment $
    Write a program that accepts a number from the terminal. If the number
    sets bit 30, then treat bits 30 to 35 as an octal number and display
    this value (I am assuming 30-35 inclusive).
    This is the 6 right-most bits: 10110101110
    $
    title ch6u5
    search monsym ; Use monitor's symbols

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

    ttyout: .priout ; TTY/keyboard input/outputs
    ttyin: .priin
    mask: ^B111111 ; Mask for bits 30-35 inclusive
    mask30: ^B100000 ; Mask for evaluating bit 30
    base10: 12 ; Input base
    base8: 10 ; Output base
    base2: 2 ; Output base for user bits num
    crlf: 15B6+12B13 ; Bit-pack a \r\n
    char: block 1 ; Save orginal number
    getnum: asciz /Enter a number to check bits 30-35: /
    bitmsg: asciz /Your number in bits is /
    bitset: asciz /
    30-bit is set / ; User prompts and messages
    newchr: asciz /
    New number in octal: /

    start: hrroi ac1,getnum ; Load user prompt
    psout% ; Display to TTY

    subttl input

    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Get input from keyboard
    move ac3,base10 ; User integer is in decimal
    nin% ; Get number
    erjmp done ; Or error if can't

    movem ac2,char ; Save original number, need later
    hrroi ac1,bitmsg ; Load "bit message"
    psout% ; Display it
    move ac1,ttyout ; Display num to TTY
    move ac3,base2 ; Display as bit string
    nout% ; Print it
    erjmp done ; Or error if can't

    and ac2,mask30 ; Match num against 30bit
    jumpe ac2,done ; Zero? Not a special number

    subttl output

    set: hrroi ac1,bitset ; Signal bit 30 set
    psout% ; Print to TTY
    move ac2,char ; Fetch original number
    and ac2,mask ; Mask off bits 30-35
    hrroi ac1,newchr ; Load new char message
    psout% ; Display to TTY
    move ac1,ttyout ; ditto
    move ac3,base8 ; Output as octal
    nout% ; Send ac2
    erjmp done ; Exit either way

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program
    end start ; Tell assembler it's done
    --
    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 Thu Jun 18 13:59:24 2026
    From Newsgroup: alt.lang.asm

    ch6u6.mac

    This program wants you prove that two bit strings entered will be:
    char1 XOR char2 = ( (NOT char1) AND char2 )
    IOR ( char1 AND (NOT char2) )

    The confusing part is that the Longo text speaks about NOT as if it is
    an opcode. It's not (pun not not intended). The display font for it in
    the text even matches XOR and AND. The Gorin text does mention an opcode
    to get a complement, but it's SETCM.

    @exec ch6u6
    LINK: Loading
    [LNKXCT CH6U6 execution]
    Enter binary string one: 10101
    Enter binary string two: 101
    The results using AND, IOR, NOT: 10000
    The results using only XOR: 10000
    @cont
    Enter binary string one: 1010
    Enter binary string two: 111
    The results using AND, IOR, NOT: 1101
    The results using only XOR: 1101

    comment $
    Accept two binary words using NIN% base 2. Perform AND, IOR, and NOT
    operations yielding the XOR of the words. Display (NOUT%) the results
    using base 2. Using the same words, XOR them and display the results
    to see they are the same as the previous calculations.
    There's no "NOT" opcode. SETCM is what you're likely supposed to
    use.
    $
    title ch6u6
    search monsym ; Use monitor's symbols

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

    char1: block 1 ; Storage for the first word
    char2: block 1 ; and the second word
    ttyout: .priout ; TTY/keyboard input/outputs
    ttyin: .priin
    base2: 2 ; Output base for user bits num
    get1: asciz /Enter binary string one: / ; User prompts and messages get2: asciz /Enter binary string two: /
    andres: asciz /The results using AND, IOR, NOT: /
    xorres: asciz /
    The results using only XOR: /

    start: hrroi ac1,get1 ; Load 'string one' message
    psout% ; Print it

    subttl input
    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Get from keyboard
    move ac3,base2 ; base 2
    nin% ; the number
    erjmp done ; Handle error (or not)
    setam ac2,char1 ; Save number 1

    hrroi ac1,get2 ; Load 'string two' message
    psout% ; and print it
    move ac1,ttyin ; Get from keyboard
    move ac3,base2 ; base 2
    nin% ; the number
    erjmp done ; Handle error (or not)
    setam ac2,char2 ; Save number 2

    subttl calculate and output
    hrroi ac1,andres ; Print 'and' result before we
    psout% ; need to use those accumulators

    ; How nice of the text to give us the algorithm for this. We have plenty
    ; of registers on the PDP-10, let's use them so as not to clobber memory
    ; because we need the orginal values later for the XOR part of this.
    ; char1 XOR char2 = ( (NOT char1) AND char2 ) IOR ( char1 AND (NOT char2) )
    setcm 4,char1 ; Complement mem at char1
    move 5,char2 ; Fetch char2 from memory
    and 4,5 ; First part is done, in 4
    move 6,char1 ; Fetch char1 from memory
    setcm 7,char2 ; Complement mem at char2
    and 6,7 ; Second part is done, in 6
    ior 4,6 ; Final result in 4

    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac2,4
    move ac1,ttyout
    move ac3,base2
    nout%
    erjmp done

    hrroi ac1,xorres ; Load 'xor' message
    psout% ; Print to TTY
    setm 4,char1 ; Fetch char1 again
    setm 5,char2 ; Fetch char2 again
    xor 4,5 ; Do xor part of algorithm
    move ac2,4 ; Read to print it
    move ac1,ttyout ; Print to TTY
    move ac3,base2 ; Print as binary
    nout%
    erjmp done ; Handle error (or not)

    done: haltf% ; Exit to monitor
    jrst start ; Restart program?
    end start ; Assembler is done
    --
    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 Mon Jun 22 10:52:45 2026
    From Newsgroup: alt.lang.asm

    ch6u7.mac

    Demo a jump table. This is the last program in chapter 6 then onto
    chapter 7.

    @exec ch6u7
    MACRO: ch6u7
    LINK: Loading
    [LNKXCT CH6U7 execution]
    Input a 1, 2, or 3 to demo a jump table: 1
    ONE
    @cont
    Input a 1, 2, or 3 to demo a jump table: 2
    TWO
    @cont
    Input a 1, 2, or 3 to demo a jump table: 3
    THREE
    @cont
    Input a 1, 2, or 3 to demo a jump table: 4
    @

    comment $
    Accept a character from the terminal. If the character is a 1, 2, or
    3, then index into the appropriate position in a jump table that
    points to locations that print ONE, TWO, or THREE.
    $
    title ch6u7
    search monsym

    ac1=1
    ac2=2
    ac3=3

    ttyin: .priin ; Input from keyboard
    base10: 12 ; Base 10 in octal
    inmesg: asciz /Input a 1, 2, or 3 to demo a jump table: /
    crlf: 15B6+12B13 ; Bit-pack a \r\n

    start: hrroi ac1,inmesg ; Prompt user for integer
    psout% ; Display message

    subttl input

    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Load input device
    move ac3,base10 ; Indicate radix
    nin% ; Get integer
    erjmp done ; Handle error

    caile ac2,3 ; If greater than 3 this is
    jrst done ; an error. Exit.
    caige ac2,1 ; Same with less than 1
    jrst done
    subi ac2,1 ; The jump table is zero-indexed
    jrst tbl(ac2) ; Valid option, use as idx 2 tbl

    subttl jump table

    tbl: jrst tbl.1 ; Jump table via index
    jrst tbl.2
    jrst tbl.3


    tbl.1: hrroi ac1,[asciz /ONE/] ; Table entry for ONE
    psout%
    jumpa tbl.4 ; Skip rest of the output
    tbl.2: hrroi ac1,[asciz /TWO/] ; Table entry for TWO
    psout%
    jumpa tbl.4 ; Skip other text outputs
    tbl.3: hrroi ac1,[asciz /THREE/] ; Table entry for THREE
    psout% ; Fall-thru on this choice
    tbl.4: hrroi ac1,crlf ; Emit newline for proper
    psout% ; output after table message

    done: haltf% ; Exit to monitor
    jrst start ; Restart program?
    end start ; Assembler is done
    --
    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 Wed Jun 24 22:29:49 2026
    From Newsgroup: alt.lang.asm

    ch7u1.mac
    ch7u2.mac

    Chapter 7 is about pointers. Yup, even in assembler we suffer
    pointers. Also literals, and moving bytes in and out of memory according
    to pointers.

    The first program locates the letter "A" in a string and tells you the position. The second program simulates RDTTY%.

    @exec ch7u1
    LINK: Loading
    [LNKXCT CH7U1 execution]
    Found "A" at position 3

    comment $
    Write a program that will print the numerical positions of the
    letter "A" in a string. Use a 7-bit pointer to gain access to
    each character. You can write the string into the program via ASCIZ.

    This solution starts counting at postion 1, not zero, and accounts
    for the character not being in the string at all.
    $
    title ch7u1
    search monsym

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    iter=4 ; Loop iteration counter

    strptr: point 7,[asciz /BCADEF/] ; String, move "A" around to test fndmsg: asciz /Found "A" at position /
    base: 12 ; Base 10 decimal

    start: setz iter, ; Clear counter
    loop: addi iter,1 ; Track position as we move
    ildb ac1,strptr ; Load next byte
    skipn ac1 ; If it's asciz's 0 we're at end
    jrst notfnd ; and thus didn't find it
    caie ac1,"A" ; Is it "A"
    jrst loop ; No, keep checking

    hrroi ac1,fndmsg ; Load found message
    psout% ; Print to TTY
    move ac2,iter ; Set up for NOUT%
    move ac1,[.priou] ; Set primary output w/literal
    move ac3,base ; Decimal base output
    nout% ; Print position
    erjmp [ move 1,[point 7,[asciz /Error./]]
    psout%
    haltf% ] ; Error-handling dance

    notfnd: haltf% ; Exit to monitor, found or not
    lit ; Debugger expand literals
    end start ; Assembler is finished


    The next program was rough, because it deals with walking around a
    pointer to simulate a DEL and a ctrl-U with string input. ctrl-U cancels
    the entire input line on TOPS-20 so that's what my handling of ctrl-U
    ("2" in the program) does in my program.

    @exec ch7u2
    LINK: Loading
    [LNKXCT CH7U2 execution]
    Enter a string, 1=DEL, 2=ctrl-U, Enter=END: ab1cd1e

    The rendered string: ace
    @cont
    Enter a string, 1=DEL, 2=ctrl-U, Enter=END: abcdef1

    The rendered string: abcde
    @cont
    Enter a string, 1=DEL, 2=ctrl-U, Enter=END: abcdef2

    The rendered string:
    @

    comment $
    Write a program that simulates an RDTTY% by looping over a PBIN%. Use
    1 to delete a character, 2 as a ctrl-U, and a carriage return to
    terminate the input loop. Print the message after accepting it.
    Ex:
    AB1CD1E
    ACE
    $
    title ch7u2
    search monsym ; Use monitor's symbols

    ac1=1 ; Label used accum. General input
    ac2=2 ; Generally used for pointers
    ac3=3 ; Generally used for ADJBP
    count=4 ; Track number of entered chars

    size==12 ; Don't show 'size' in debugger
    buffer: block size ; 10 words * 5 = 50 ASCII chars
    ; Each block is 5 chars
    ptrbuf: point 7,buffer ; Pointer to buffer
    etrmsg: asciz /Enter a string, 1=DEL, 2=ctrl-U, Enter=END: /
    renmsg: asciz /
    The rendered string: / ; User prompts and messages

    start: hrroi ac1,etrmsg ; Prompt user for string
    psout% ; Write to TTY

    move ac2,ptrbuf ; Get pointer to buffer for input
    setz ac1, ; Zero out ac1, it will get chars
    setz count, ; No characters input to start
    getchr: pbin% ; Main char input loop, to ac1
    cain ac1,15 ; \r? If so, it signals end
    jrst lf
    cain ac1,"1" ; Is it the delete signal (1)?
    ; Once the user inputs "1", back up the pointer by moving a -1 to an
    ; accumulator then using ADJBP on the accumulator that has the buffer-pointer. ; After, the result is left in ac3 - move this result back to where the
    ; buffer-pointer points, thus updating the contents. Express as a literal.
    jrst [ movni ac3,1
    adjbp ac3,ac2
    movem ac3,ac2
    jumpa getchr] ; Back up pointer in buffer-pointer
    ; using -1, then re-enter getchar loop

    cain ac1,"2" ; Is it the ctrl-u/blank line char?
    jrst [ movn ac3,count
    adjbp ac3,ac2
    movem ac3,ac2
    jumpa getchr] ; Like delete, move pointer back in
    ; buffer-pointer, but this time
    ; according to total chars entered

    idpb ac1,ac2 ; Stuff char to buff, inc pointer
    addi count,1 ; Record that we entered a character
    jrst getchr ; Get next character

    lf: pbin% ; Eat \n, after \r from above
    setz ac1, ; Zero out ac1 to put 0
    idpb ac1,ac2 ; Null terminator for PSOUT%

    hrroi ac1,renmsg ; Load rendered string message
    psout% ; Display it
    move ac1,ptrbuf ; Load pointer to buffer
    psout% ; Print buff contents to TTY
    haltf% ; End program
    jrst start ; Restart program
    lit ; Debugger to show literals
    end start ; Assembler is done
    --
    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 Jun 26 21:36:31 2026
    From Newsgroup: alt.lang.asm

    ch7u3.mac
    ch7u4.mac

    The first program emulates MID$ (from BASIC). TOPS-20 has a BASIC so I
    could see how it worked. The second program reads from the terminal and
    stores strings. Then you read from that memory and convert to integers.

    @exec ch7u3
    LINK: Loading
    [LNKXCT CH7U3 execution]
    Enter a short string to demo MID$: Where is Paris?
    Enter an integer position to begin the substring: 10
    Enter an integer reflecting the substring length: 5
    Paris
    @cont
    Enter a short string to demo MID$: Hello world
    Enter an integer position to begin the substring: 0
    Invalid start position

    comment %
    Write a program that simulates a MID$ (in BASIC) function. The program
    should accept a string and two numbers and then print the partial string.
    Ex:
    @basic

    READY
    10 a$ = "Where is Paris?"
    20 print mid$( a$, 10, 5 )
    run

    NONAME.B20
    Thursday, June 25, 2026 11:54:54

    Paris
    %
    title ch7u3
    search monsym

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    count=4 ; How many chars in substring?

    size==36 ; 30 dec, don't show sym in debugger buffer: block size ; 30 words * 5 = 150 ASCII chars ptrbuf: point 7,buffer ; Pointer to input buffer
    base10: 12 ; 10 decimal, base we in/output with pos: 0 ; Starting postion of substring
    ttyout: .priou ; Display device
    ttyin: .priin ; Keyboard input device

    strmsg: asciz /Enter a short string to demo MID$: /
    inimsg: asciz /Enter an integer position to begin the substring: /
    endmsg: asciz /Enter an integer reflecting the substring length: /
    outmsg: asciz /
    The substring is / ; User prompts and messages

    subttl input
    start: hrroi ac1,strmsg ; Load user prompt
    psout% ; Display
    move ac1,ptrbuf ; Set up buffer for RDTTY%
    movei ac2,size-1 ; Num chars to read, allow for null end
    setz ac3, ; No ctrl-r, not needed on modern TTY
    rdtty% ; Read the user's test string
    erjmp error ; Handle error

    getn1: hrroi ac1,inimsg ; Load prompt to get start pos
    psout% ; Display it
    ; nin% wants device, radix to 1, 3 and puts results in ac2
    move ac1,ttyin ; Ready NIN%
    move ac3,base10 ; Input base is decimal
    nin% ; Get starting pos number
    erjmp error ; Handle error
    caig ac2,0 ; Don't allow zero or less
    jrst [move ac1,[point 7,[asciz /Invalid start position/]]
    psout%
    jumpa done] ; Exit w/error if not > 1
    subi ac2,1 ; Adjust start position from zero
    ; indexing to one, which is what
    ; a user would expect
    movem ac2,pos ; Save starting position

    getn2: hrroi ac1,endmsg ; Load prompt to get num chars
    psout% ; Display it
    move ac1,ttyin ; Read from TTY
    move ac3,base10 ; Still using decimal
    nin% ; Get num chars to read
    erjmp error ; Handle error
    move count,ac2 ; Save num of chars in substring

    subttl substring
    subs.1: move ac2,ptrbuf ; Load pointer to char buffer
    move ac3,pos ; Fetch starting substring position
    adjbp ac3,ac2 ; Move pointer to new starting pos
    movem ac3,ac2 ; Save result into memory
    subs.2: ildb ac1,ac3 ; Load next byte in ptr ac3 for ac1
    cain ac1,15 ; \r? If so, we're end-of-string
    jrst done ; with nothing more to print, exit
    pbout% ; Print ac1's character
    sojg count,subs.2 ; Loop if still chars (count)

    done: haltf% ; Exit to monitor
    jrst start ; Restartable program

    ; The error message is very generic because this is only an exercise
    error: hrroi ac1,[point 7,[asciz /Error, can't demo MID$/ ] ]
    haltf% ; Exit to monitor
    lit ; Display literals on debug
    end start ; Assembler's job is done


    This program was harder because the text doesn't spend much time
    explaining using NIN% pointed at memory. It gets numbers as strings,
    then ORs them and outputs them as numbers. Think atoi() in C. This
    program also uses a reprompter (ctrl-r), though outside a paper TTY it's
    not that useful.

    @exec ch7u4
    LINK: Loading
    [LNKXCT CH7U4 execution]
    Enter first 5-bit binary number: 00101
    Enter second 5-bit binary number: 01010
    Final result: 01111

    comment $
    Set up an RDTTY%/NIN% to accept two 5-bit binary numbers. IOR the
    numbers; then NOUT% the result in a field of width 5, with leading
    zeroes.
    Additional info on using RDTTY%/NIN% in conjunction: https://www.bourguet.org/v2/pdp10/jsys-user/chap2 , section 2.9
    $
    title ch7u4
    search monsym

    ac1=1 ; Label used accumulators
    ac2=2
    ac3=3
    ac4=4

    num1: block 2 ; 2 * 5 = 10 chars space
    num2: block 2 ; 2 * 5 = 10 chars space
    ptrnm1: point 7,num1 ; Pointer to first buffer
    ptrnm2: point 7,num2 ; Pointer to second buff

    msg1: asciz /Enter first 5-bit binary number: /
    msg2: asciz /Enter second 5-bit binary number: /
    finmsg: asciz /Final result: / ; User messages and prompts

    start: hrroi ac1,msg1 ; Prompt for first number
    psout% ; Display message to TTY
    move ac1,ptrnm1 ; Set up buffer for RDTTY%
    movei ac2,5+2 ; 5 chars plus \r\n
    hrroi ac3,[asciz /First number? /] ; Reprompter message
    rdtty% ; Get first number
    erjmp [move ac1, [point 7, [asciz /Error getting first number /]]
    psout%
    haltf%] ; Handle error here

    hrroi ac1,msg2 ; Prompt for second number
    psout% ; Print to TTY
    move ac1,ptrnm2 ; Set up buffer for RDTTY%
    movei ac2,5+2 ; 5 chars plus \r\n
    hrroi ac3,[asciz /Second number? /]
    rdtty% ; Get second number
    erjmp [move ac1, [point 7, [asciz /Error getting num 2 /]]
    psout%
    haltf%] ; Handle error on num2
    hrroi ac1,finmsg ; Load results message
    psout% ; Print to TTY

    ; This section uses NIN% to read the inputted data from memory and
    ; convert it. In this case, give ac1 a pointer to the buffer.
    ; nin% wants device, radix to 1, 3 and puts results in ac2
    conv: move ac1,ptrnm1 ; Load pointer to buffer, num1
    movei ac3,2 ; Convert to base binary
    nin% ; Fetch number
    erjmp [move ac1, [point 7, [asciz /Conversion error/ ]]
    psout%
    haltf%] ; Handle conv error

    move ac4,ac2 ; Park this for a moment
    move ac1,ptrnm2 ; Load pointer to buff/num1
    movei ac3,2 ; Convert to base binary
    nin% ; Fetch second number
    erjmp [move ac1, [point 7, [asciz /Conversion error/ ]]
    psout%
    haltf%] ; Handle 2nd conv error

    or: ior ac4,ac2 ; Perform the IOR, result in ac4
    ; nout% wants device, number, base in accum 1,2,3 and erjmp
    move ac1,[.priou] ; Indicate TTY as output
    move ac2,ac4 ; The resulting number
    movei ac3,2 ; Indicate binary base output

    ; The left half of ac3 controls the display of the number with NOUT%
    ; Each bit sets a feature. Note "NO%*" type values do not seem to work
    ; even though the text mentions them. Use a binary string instead.
    hrli ac3,^B1110000000000101 ; Leading 0's, 5 places
    nout% ; Print resulting number
    erjmp done ; Handle error (or not)

    done: haltf% ; Exit to monitor
    jrst start ; Restart program
    lit ; Debugger expands literals
    end start ; Assembler is done
    --
    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