| | This program demonstrates some of the simplest | 680x0 assembly language instructions, I/O, | and program structure. | | This program is very heavily commented because it is | your main introduction to the language. You should | comment more sparingly. Not too sparingly, please. | | | The data section will contain constant data, | and any non-stack storage space your program | uses. The assembler directives .ascii, .asciz, | .skip, and .byte are useful here. | .data prompt: .asciz "Please type a character: " newline: .byte 012 | | You will use the C compiler (cc) to assemble your | programs (cc -o myprogram myprogram.s). | Any source file whose name ends with | ".s" is interpreted by cc as an assembly language | file. To get cc to treat your code like a complete | program, you need to specify the starting point of | of your program with the "_main" label. | | When your program begins execution, the top item on the | stack is a return address. Thus, your main program | should end with an "rts" instruction. To avoid bus | errors and segmentation faults when this rts gets | executed, you will need to make sure the stack pointer | is back where it started. So any subroutine that | puts stuff on the stack should clean up after itself. | .text .align 1 .globl _main _main: movl #prompt, a0 jsr putstring jsr _getchar jsr capitalize jsr putchar movb newline, d0 jsr putchar rts | | Subroutine: putchar (different from the library function | "_putchar") | | This subroutine is perhaps unnecessary, since it | takes one instruction to set up (put the parameter | in d0), while _putchar also takes only one instruction | to set up (put the parameter on the stack). But | _putchar does not clean up the stack when it is through, | and using d0 for output is consistent with the way | _getchar uses d0 for input. So I am going to use "putchar" | to make my main program code a little cleaner. | | You might argue that assembly code should be as tight | as possible--built for speed, not for readability--and | that my "putchar" just adds a couple instructions to every | character of output. But I/O is so slow anyway | that the extra instructions do not affect running time. | It is in the inner computational loops that you want to | write streamlined code at the expense of clarity, and in | such cases, your comments should expand to fill the | readability gap. | | Precondition: The character to be printed is | stored in d0 (more precisely, in the lowest order | byte of d0. | | Postcondition: the character has been written to | standard output by the library function _putchar. | putchar: movl d0, sp@- jsr _putchar addl #4, sp rts | | Subroutine: putstring | | Precondition: a0 contains the address of a null-terminated | string. | | Postconditions: The null-terminated string has been printed | to standard output, and a0 now points to the null character | at the end of the string. | putstring: movb a0@+, d0 tstb d0 beq ps_end movl a0, sp@- jsr putchar movl sp@+, a0 bra putstring ps_end: rts | | Subroutine: capitalize | | Precondition: The low order byte of d0 contains a character. | | Postcondition: If the character was a lower-case letter (ASCII), | then the low order byte of d0 contains the upper-case version | of the same letter. Otherwise, d0 is unchanged. | capitalize: cmpb #97, d0 blt cap_end cmpb #122, d0 bgt cap_end subb #32, d0 cap_end: rts