home *** CD-ROM | disk | FTP | other *** search
/ Oakland CPM Archive / oakcpm.iso / cpm / asmutl / meyertut.ark / MEYER03.TXT < prev    next >
Text File  |  1987-12-04  |  8KB  |  191 lines

  1.                      CP/M Assembly Language
  2.                      Part III: Calling BDOS
  3.                           by Eric Meyer
  4.  
  5.      Last time we learned about the structure of the 8080 CPU,
  6. and wrote a simple little program to move around bytes (or words)
  7. of data with it. We found, however, that we couldn't tell we had
  8. done anything. Now we need to learn how to communicate with the
  9. terminal, print messages, and get keyboard input.
  10.  
  11.  
  12. 1. The CALL and JMP instructions
  13.      It's good practice to divide assembler code into separate
  14. modules. As you probably can imagine, once you have a few dozen
  15. (or hundred) lines of code, things start looking disorganized.
  16.      Then, of course, you need to be able to run each module of
  17. code in the proper sequence. By nature, the 8080 CPU just goes
  18. along executing one instruction after another, as it finds them.
  19. But there is a pair of instructions that cause it to go and
  20. execute code at some other location instead. The JMP (jump)
  21. instruction is like GOTO (a branch) in many languages; it simply
  22. goes and begins executing code someplace else.
  23.      The CALL instruction, like GOSUB (a subroutine call), does
  24. the same thing, but remembers where you were before, and will
  25. return there when it finds a RET instruction.
  26.      Both JMP and CALL take an address (16-bit data value) for an
  27. argument. This is almost always a label marking the beginning of
  28. the code you want to execute. For example:
  29.  
  30.                     instr1
  31.                     instr2
  32.                     JMP     LABEL
  33.                     instr3
  34.           LABEL:    instr4
  35.                     instr5
  36.  
  37. actually will execute instructions 1, 2, 4, 5, skipping instr3.
  38. Similarly,
  39.  
  40.                     instr1
  41.                     CALL    LABEL
  42.                     instr2
  43.                     RET
  44.           LABEL:    instr3
  45.                     instr4
  46.                     RET
  47.  
  48. will execute the instructions in the order 1, 3, 4, 2.
  49.      As an exercise, you might want to go back to the byte mover
  50. program of the last installment, and rewrite the instructions
  51. that move a byte from source to destination as a subroutine,
  52. which you could then CALL any number of times in sequence.
  53.  
  54.  
  55. 2. BDOS Calls
  56.      In Part I, I said that assembler differed from higher-level
  57. languages in that there were no prepared subroutines for you to
  58. call, you had to write every byte of code yourself.
  59.      Actually, this isn't strictly true.
  60.      CP/M has a number of routines in the BDOS (basic disk
  61. operating system) which are designed to be called as subroutines,
  62. and allow you to do useful things like send characters to and
  63. from the terminal, read and write disk files, etc.
  64.      This is the only way to do these tasks without knowing a lot
  65. of specific detail about (or duplicating a lot of the code in)
  66. the BIOS (basic input/output system) that allows CP/M to run on
  67. your particular computer.
  68.      In brief, the operating system has already been told how to
  69. do these things -- all you have to do is ask it to do them.
  70.      There are several dozen "BDOS calls". At address 0005H in
  71. memory, there is always a JMP instruction which leads into the
  72. operating system.
  73.      Thus you make a BDOS call by setting up certain initial
  74. values, and then CALLing address 0005H. First you need to decide
  75. which BDOS function you want. Each has a code number, which has
  76. to be loaded into the C register. Then, if necessary, you put
  77. some additional information into the D-E registers. Then you CALL
  78. 0005H. The whole thing winds up looking like:
  79.  
  80. MVI  C,xx    ;put the BDOS function number here
  81. LXI  D,xxxx  ;(may need some more data here)
  82. CALL 0005H   ;ask the BDOS to do it
  83.  
  84.      Our immediate need is to communicate with a program. Here
  85. are three BDOS calls to do the job.
  86.      Function 2 sends a character to the screen. You have to put
  87. the desired ASCII code into the E register (the D register isn't
  88. used here):
  89.  
  90. MVI  C,2    ;console output function
  91. MVI  E,xx   ;put the character you want here
  92. CALL 0005H  ;ask BDOS to do it
  93.  
  94.      This could get tedious for a whole string. We could write a
  95. subroutine to use this call repeatedly, but for now let's be
  96. lazy.
  97.      Function 9 sends a whole string of characters to the screen.
  98. You have to use the $ character to mark the end of the string,
  99. and to put the address where the string starts into the D-E pair.
  100. The following complete program, which you can assemble and run,
  101. prints out "Hello world!":
  102.  
  103.           ORG    0100H
  104.           MVI    C,9      ;print string function
  105.           LXI    D,STRING ;address of the string to print
  106.           CALL   0005H    ;ask BDOS to do it
  107.           RET
  108.  STRING:  DB     'Hello world!$'
  109.                 END
  110.  
  111.      Function 1 gets a character from the keyboard. It doesn't
  112. require any other information; you simply:
  113.  
  114. MVI    C,1    ;console input function
  115. CALL   0005H  ;ask BDOS to do it
  116.  
  117. and the BDOS will wait for a key to be pressed. The ASCII code of
  118. the key will be returned to your program in the A register. The
  119. following program will ask you a question and accept your
  120. response:
  121.  
  122.          ORG    0100H
  123.          MVI    C,9       ;print string
  124.          LXI    D,QUESTN  ;(this one)
  125.          CALL   0005H
  126.          MVI    C,1       ;get key
  127.          CALL   0005H
  128.          RET              ;who cares?
  129.  QUESTN: DB     'Are you excited? (Y/N) $'
  130.          END
  131.  
  132.      At the point where this program RETurns, the ASCII value of
  133. the key you typed is in the A register. Sadly, we don't know how
  134. to examine or test this yet, so there's no more to do for now.
  135.  
  136.  
  137. 3. It Talks, It . . .
  138.      Now we can rewrite our "byte mover" program from Part II, so
  139. that it uses a neat subroutine to move each byte, and tells us
  140. what it's doing. Let's call this BYTEMOV2.ASM:
  141.  
  142. BDOS   EQU    0005H          ;define the BDOS entry address
  143.        ORG    0100H          ;code begins here
  144.        MVI    C,9            ;BDOS print string fn
  145.        LXI    D,HELLO        ;i.d. message
  146.        CALL   BDOS           ;do it
  147.        MVI    C,9
  148.        LXI    D,DEST         ;show the original string
  149.        CALL   BDOS
  150.        LXI    H,SOURCE       ;point to source
  151.        LXI    D,DEST         ;point to destination
  152.        CALL   MOVBYT         ;move one byte
  153.        CALL   MOVBYT         ;move the second byte
  154.        MVI    C,9
  155.        LXI    D,DONE         ;explain that it's changed
  156.        CALL   BDOS
  157.        MVI    C,9
  158.        LXI    D,DEST         ;show what it is now
  159.        CALL   BDOS
  160.        RET                   ;all done, return.
  161.   ;subroutine to move a byte
  162.   MOVBYT: MOV    A,M            ;fetch byte from memory
  163.           XCHG                  ;point to destination
  164.           MOV    M,A            ;store byte
  165.           XCHG                  ;point back to source
  166.           INX    H              ;increment source
  167.           INX    D              ;increment destination
  168.           RET                   ;all done
  169.   ;data area... note "$" char so we can use BDOS 9
  170.   SOURCE: DB     'hi$'          ;move bytes from here
  171.   DEST:   DB     '??$'          ;to here
  172.   ;messages
  173.   HELLO:  DB     'Byte mover program 2-- string was: $'
  174.   DONE:   DB     ' and it is now: $'
  175.           END
  176.  
  177.      When you assemble and run this program, you will know that
  178. it actually did something; what you should of course see is:
  179.  
  180. A>bytemov2<cr>
  181.  
  182.       Byte mover program 2 string was ?? and it is now hi. Note
  183. how easy it would be to increase the string length -- just add in
  184. the extra characters at SOURCE and DEST, and call MOVBYT a few
  185. more times.
  186.  
  187.  
  188. 4. Coming Up . . .
  189.      In future installments we'll learn some more assembler
  190. instructions, including arithmetic and conditional branches.
  191.