Difference between revisions of "CSC231 Homework 7 Solution Programs"

From dftwiki3
Jump to: navigation, search
(Created page with "--~~~~ ---- =Program 1= * This solution is from Gavi and shows she got the hints I gave the class about this array of character. The trick here is that since all the characters...")
 
(Output)
 
(12 intermediate revisions by the same user not shown)
Line 67: Line 67:
 
</source>
 
</source>
 
<br />
 
<br />
 +
 +
Another good solution that doesn't use the array is provided by Naomi:
 +
 +
<br />
 +
<source lang="asm">
 +
;;; hw7a.asm
 +
;;; 231a-ad
 +
;;; Naomi Long
 +
;;;
 +
;;; This program prints the decimal representation of the hex number
 +
;;; 0x1234ABCD and then prints out the hex digits. The output is shown
 +
;;; below, sandwiched between two prompts:
 +
;;;
 +
;;; [231a-ad@grendel ~/hw7]$ ./hw7a
 +
;;; x = 305441741 = 0x1234ABCD
 +
;;; [231a-ad@grendel ~/hw7]$
 +
 +
%include "asm_io.inc"
 +
 +
;;;  -------------------------
 +
;;;  data segment
 +
;;;  -------------------------
 +
 +
section .data
 +
x dd 0x1234ABCD
 +
xeq db "x = ",0x00
 +
eq db " = 0x",0x00
 +
 +
;;;  -------------------------
 +
;;;  code area
 +
;;;  -------------------------
 +
 +
section .text
 +
global  asm_main
 +
asm_main:
 +
;;; print "x = "
 +
mov eax, xeq
 +
call print_string ; prints "x = "
 +
 +
;;; print decimal representation and " = 0x"
 +
mov eax, dword[x]
 +
call print_int ; prints 305441741
 +
mov eax, eq
 +
call print_string ; prints " = 0x"
 +
 +
;;; print hex representation
 +
mov ecx, 8 ; 8 hex digits to loop over
 +
start:
 +
mov eax, dword[x] ; gets current hex rotation
 +
rol eax, 4 ; moves first hex to last position
 +
mov dword[x], eax ; saves rotation
 +
and eax, 0x0000000f ; remove all but last hex digit
 +
 +
cmp eax, 10 ; check if hex digit letter or number
 +
jae letr ; jump to treat letter as ascii char
 +
 +
call print_int ; prints last hex digit if number
 +
jmp loop ; skip to end of loop
 +
 +
letr: add eax, 'A'-10 ; offset dec to ascii character
 +
call print_char ; prints last hex number as ascii char
 +
 +
loop: loop start ; loop to print all 8 hex digits
 +
 +
call print_nl ; prints new line after loop is done
 +
 +
;;;  return to C program
 +
ret
 +
</source>
 +
<br />
 +
<br />
 +
<br />
 +
=Comments=
 +
==Comments about the programs submitted from the class==
 +
 +
* Put a header above each function.  In it put
 +
** the name of the function
 +
** the parameters it receives
 +
** whether it modifies any of the registers
 +
** what it returns, if any
 +
* Avoid unreachable code
 +
 +
          ret
 +
          ret
 +
 +
* Put the last '''ret''' instruction at the end of the '''main''' function, not at the end of the listing.
 +
* Don't call functions '''func1''' and '''func2'''.
 +
* '''If you are working with characters, use a ''byte'' register, not a word or double word register.'''
 +
* Use self-documenting labels that will help the reader follow the code better:
 +
** Instead of
 +
 +
              cmp        al, 9
 +
              jgt        grthn
 +
              ...
 +
grthn:
 +
 +
::use
 +
 +
              cmp        al, 9
 +
              jgt        printLetter
 +
              ...
 +
printLetter:
 +
 +
* Don't be afraid to be clever!
 +
 +
  xEqual    db      "x = ", 0x00
 +
  equal      equ      xEqual+1
 +
 +
* Don't be afraid to double check what you write:
 +
 +
                add      al, 'A'
 +
                sub      al, 10
 +
 +
:can be performed with just 1 operation:
 +
 +
                add      al, 'A'-10
 +
 +
==Comments about the Hints==
 +
 +
* See solution program above...
 +
* Pushing the hints one more step: A python program to generate a lookup table in assembly!
 +
 +
<br />
 +
<source lang="python">
 +
# generateTableLookupHexadecimal.py
 +
# D. Thiebaut
 +
# Generates a lookup table for translating a byte into its string equivalent in hex.
 +
# Note: This is for Python Version 2.X.  For Version 3.X, add parentheses to the print
 +
# statements.
 +
 +
# generate table declaration
 +
s = "table\tdb\t"
 +
 +
# generate 256 strings of 2 bytes representing the 2 hex digits
 +
 +
for i in range(256):
 +
    #print "%d %02X" % (i, i )
 +
    if ( i!=0 and i%8==0 ):
 +
        s += "\n\tdb\t"
 +
    else:
 +
        if ( i!=0 ):
 +
            s += ", "
 +
    s += '"%02X"' % i
 +
 +
print s
 +
 +
 +
</source>
 +
<br />
 +
===Output===
 +
<code><pre>
 +
table db "00", "01", "02", "03", "04", "05", "06", "07"
 +
db "08", "09", "0A", "0B", "0C", "0D", "0E", "0F"
 +
db "10", "11", "12", "13", "14", "15", "16", "17"
 +
db "18", "19", "1A", "1B", "1C", "1D", "1E", "1F"
 +
db "20", "21", "22", "23", "24", "25", "26", "27"
 +
db "28", "29", "2A", "2B", "2C", "2D", "2E", "2F"
 +
db "30", "31", "32", "33", "34", "35", "36", "37"
 +
db "38", "39", "3A", "3B", "3C", "3D", "3E", "3F"
 +
db "40", "41", "42", "43", "44", "45", "46", "47"
 +
db "48", "49", "4A", "4B", "4C", "4D", "4E", "4F"
 +
db "50", "51", "52", "53", "54", "55", "56", "57"
 +
db "58", "59", "5A", "5B", "5C", "5D", "5E", "5F"
 +
db "60", "61", "62", "63", "64", "65", "66", "67"
 +
db "68", "69", "6A", "6B", "6C", "6D", "6E", "6F"
 +
db "70", "71", "72", "73", "74", "75", "76", "77"
 +
db "78", "79", "7A", "7B", "7C", "7D", "7E", "7F"
 +
db "80", "81", "82", "83", "84", "85", "86", "87"
 +
db "88", "89", "8A", "8B", "8C", "8D", "8E", "8F"
 +
db "90", "91", "92", "93", "94", "95", "96", "97"
 +
db "98", "99", "9A", "9B", "9C", "9D", "9E", "9F"
 +
db "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7"
 +
db "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF"
 +
db "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7"
 +
db "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF"
 +
db "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7"
 +
db "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF"
 +
db "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7"
 +
db "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF"
 +
db "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7"
 +
db "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF"
 +
db "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7"
 +
db "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"
 +
 +
</pre></code>
 +
<br />
 +
Using this code, one can get a pointer to the string representing the hexadecimal value in, for example, '''al''':
 +
 +
        mov    al, ''someValue''
 +
        mov    bl, al                  ;bl contains the same value                                                                         
 +
        and    ebx, 0x000000ff        ;extend bl into ebx                                                                                 
 +
        shl    ebx, 1                  ;multiply ebx by 2 (because the table is a table of words)
 +
        lea    ecx, [ebx+table]        ;Load Effective Address ebx+table in ecx
 +
        mov    eax, 4
 +
        mov    ebx, 1
 +
        mov    edx, 2         ;get ready to print 2 chars
 +
        int    0x80 ;print them
 +
 +
=Problem 2=
 +
<br />
 +
<source lang="asm">
 +
;;; 10/31/2012
 +
;;; hw7b.asm
 +
;;; Yoshie Sasaki (edited by D. Thiebaut)
 +
;;;
 +
;;; This program takes a string of bytes where two characters have been
 +
;;; packed in each byte.  The first nybble (high) represents the lower
 +
;;; nybble of an uppercase ascii.  Similarly for the second (low) nybble.
 +
;;; Only ascii chars between '@' and 'O' can be represented that way
 +
;;; (@, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
 +
;;; l
 +
;;; Hexidecimal numbers 4 in the upper nibble represents chars "@ and
 +
;;; A-O" in Ascii Code. If we want to just use these chars, memory
 +
;;; can be saved. The data section can hold the lower nibbles, and the
 +
;;; fixed upper nibble can be accounted for in the code/text section.
 +
;;; The program connects the lower nibbles to the fixed upper to
 +
;;; print the desired Ascii chars. A function is used to print the contents
 +
;;; of each byte in memory. Strings from address "y" and "z" is printed.
 +
;;;
 +
;;; Example:
 +
;;; yLen    dd    18
 +
;;; y        db    0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
 +
;;;          db    0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
 +
;;;
 +
;;; get decoded as
 +
;;; MEED  CANDID OBAMA AND BONI OF GANA
 +
;;;
 +
;;; To Link and Run:
 +
;;;  nasm -f elf -F stabs hw7b.asm
 +
;;;  gcc -m32 -o hw7b driver.c asm_io.o hw7b.o
 +
;;;  ./hw7b
 +
 +
                %include "asm_io.inc"
 +
 +
            ;; -------------------------
 +
            ;; data segment
 +
            ;; -------------------------
 +
            section .data
 +
yLen    dd    18
 +
y        db    0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
 +
        db    0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
 +
 +
zLen    dd    24
 +
z        db    0xef, 0x07, 0xff, 0x40, 0xd1, 0x41, 0xd5, 0x03, 0x81
 +
        db    0xee, 0x5c, 0x01, 0xe4, 0x02, 0x14, 0x0d, 0x1e, 0x0d
 +
        db    0xf1, 0xe0, 0x9e, 0x0c, 0x9d, 0x10
 +
 +
            ;; -------------------------
 +
            ;; code area
 +
            ;; -------------------------
 +
            section .text
 +
            global  asm_main
 +
asm_main:
 +
;;;
 +
;;; ---  Decode y string ---
 +
;;;
 +
            mov eax, 0
 +
            mov ecx, dword[yLen] ;save memory length
 +
            mov edx, y
 +
 +
            ;Go through bytes in memory & print char A to O
 +
fory:        call printByte
 +
            inc edx            ;inc byte count
 +
            loop fory
 +
            call print_nl
 +
 +
;;;
 +
;;; --- Decode z string ---
 +
;;;
 +
 +
            mov eax, 0
 +
            mov ecx, dword[zLen];save memory length
 +
            mov edx, z
 +
 +
            ;Go through bytes in memory & print char A to O
 +
forz:        call printByte
 +
            inc edx            ;inc byte count
 +
            loop forz
 +
            call print_nl
 +
 +
;;;
 +
;;; --- END (return to C program)
 +
;;;
 +
        ret
 +
 +
;;; -------------------------------------------------------------
 +
;;;  PrintByte(As in the contents of the byte in memory)
 +
printByte:  mov al, byte[edx]  ;Get next byte
 +
 +
;;;  print upper nybble...
 +
            ror al, 4          ;Rotate the upper half down
 +
            and al, 0x0F        ;Hide the rest
 +
            add al, 0x40        ;Fill the top half with set Hex val
 +
            cmp al, 0x40
 +
            jne  noSpaceU      ;Skip next step if not "@"
 +
 +
            mov al, ' '        ;Else, "@" = " "
 +
 +
noSpaceU:    call print_char
 +
 +
;;;  print lower nybble...
 +
            mov al, byte[edx]  ;Get byte again(Now looking at lower)
 +
            and al, 0x0F        ;Do the same as upper half
 +
            add al, 0x40       
 +
            cmp al, 0x40
 +
            jne  noSpaceL
 +
            mov al, ' '
 +
 +
noSpaceL:    call print_char
 +
            ret
 +
 +
</source>
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
<br />
 +
[[category:CSC231]][[Category:Homework]]

Latest revision as of 08:42, 5 November 2012

--D. Thiebaut 13:21, 1 November 2012 (EDT)


Program 1

  • This solution is from Gavi and shows she got the hints I gave the class about this array of character. The trick here is that since all the characters are listed in order in the string, you have character '0' at index 0 in the string. Character '1' at Index 1. Character '2' at Index 2... Character '9' at Index 9. And now for the magic: Character 'A' is at Index 10. Character 'B' at Index 11, all the way to Character 'F' at Index 15. So we do not need to test whether the number we want to print in hex is less than 10 or not. We just take the number, use it as an index in the string and pull the character that corresponds to it!


;;; ; hw7a.asm
;;; ; Gavi Levy Haskell
;;; ; 231a-ae
;;; ;
;;; ;
;;; ; Displays the contents of a double-word in decimal and
;;; ; hexadecimal.
;;; ;
;;; ; Prints:
;;; ;   x = 305441741 = 0x1234ABCD
;;; ;
;;; ;
;;; ;     nasm -f elf -F  stabs hw7a.asm
;;; ;     gcc -m32 -o hw7a driver.c asm_io.o hw7a.o
;;; ;     ./hw7a

%include "asm_io.inc"
	
	;; -----------------
	;; DATA SECTION
	;; -----------------
	section	.data
x	dd	0x1234ABCD
msg	dd	"  x = ", 0x00
msg2	dd	" = 0x", 0x00
hexChr	db	"0123456789ABCDEF"
	
	;; -----------------
	;; CODE SECTION
	;; -----------------
	section	.text
	global	asm_main
asm_main:
	mov	eax, msg
	call	print_string 	; print "  x = "
	
 	mov	eax, dword[x]
 	call	print_int	; print "305441741"

	mov	eax, msg2
	call	print_string	; print " = 0x"
	
 	mov	ecx, 8
	
for:	mov	ebx, dword[x]	; ebx <-- current rotation of x
 	rol	ebx, 4		; rotate first byte to end
 	mov	dword[x], ebx	; save current rotation in x
 	and	ebx, 0x000000F 	; keep only last digit in ebx

	mov	al, byte[hexChr + ebx]
	call	print_char	; print the character of hexChr
				; corresponding to the digit
	loop	for

	call	print_nl
	
	;; return to C program
	ret


Another good solution that doesn't use the array is provided by Naomi:


;;; hw7a.asm
;;; 231a-ad
;;; Naomi Long
;;;
;;; This program prints the decimal representation of the hex number
;;; 0x1234ABCD and then prints out the hex digits. The output is shown
;;; below, sandwiched between two prompts:
;;; 
;;; [231a-ad@grendel ~/hw7]$ ./hw7a
;;; x = 305441741 = 0x1234ABCD
;;; [231a-ad@grendel ~/hw7]$

	%include "asm_io.inc"

;;;  -------------------------
;;;  data segment
;;;  -------------------------

	section .data
	x	dd	0x1234ABCD
	xeq	db	"x = ",0x00
	eq	db	" = 0x",0x00
	
;;;  -------------------------
;;;  code area
;;;  -------------------------

	section .text
	global  asm_main
asm_main:
;;; print "x = "
	mov	eax, xeq
	call	print_string		; prints "x = "
	
;;; print decimal representation and " = 0x"
	mov	eax, dword[x]
	call	print_int		; prints 305441741
	mov	eax, eq			
	call	print_string		; prints " = 0x"
	
;;; print hex representation
	mov	ecx, 8			; 8 hex digits to loop over
start:
	mov	eax, dword[x]		; gets current hex rotation
	rol	eax, 4			; moves first hex to last position
	mov	dword[x], eax		; saves rotation
	and	eax, 0x0000000f		; remove all but last hex digit
	
	cmp	eax, 10			; check if hex digit letter or number
	jae	letr			; jump to treat letter as ascii char
	
	call	print_int		; prints last hex digit if number
	jmp 	loop			; skip to end of loop
	
letr:	add	eax, 'A'-10		; offset dec to ascii character
	call	print_char		; prints last hex number as ascii char

loop:	loop 	start			; loop to print all 8 hex digits

	call	print_nl		; prints new line after loop is done
	
;;;  return to C program
	ret




Comments

Comments about the programs submitted from the class

  • Put a header above each function. In it put
    • the name of the function
    • the parameters it receives
    • whether it modifies any of the registers
    • what it returns, if any
  • Avoid unreachable code
          ret
          ret
  • Put the last ret instruction at the end of the main function, not at the end of the listing.
  • Don't call functions func1 and func2.
  • If you are working with characters, use a byte register, not a word or double word register.
  • Use self-documenting labels that will help the reader follow the code better:
    • Instead of
             cmp        al, 9
             jgt         grthn
             ...
grthn:
use
             cmp        al, 9
             jgt         printLetter
             ...
printLetter:

  • Don't be afraid to be clever!
 xEqual     db      "x = ", 0x00
 equal       equ      xEqual+1
  • Don't be afraid to double check what you write:
                add      al, 'A'
                sub      al, 10

can be performed with just 1 operation:
                add      al, 'A'-10

Comments about the Hints

  • See solution program above...
  • Pushing the hints one more step: A python program to generate a lookup table in assembly!


# generateTableLookupHexadecimal.py
# D. Thiebaut
# Generates a lookup table for translating a byte into its string equivalent in hex.
# Note: This is for Python Version 2.X.  For Version 3.X, add parentheses to the print
# statements.

# generate table declaration
s = "table\tdb\t"

# generate 256 strings of 2 bytes representing the 2 hex digits

for i in range(256):
    #print "%d %02X" % (i, i ) 
    if ( i!=0 and i%8==0 ):
        s += "\n\tdb\t"
    else:
        if ( i!=0 ):
            s += ", "
    s += '"%02X"' % i

print s


Output

table	db	"00", "01", "02", "03", "04", "05", "06", "07"
	db	"08", "09", "0A", "0B", "0C", "0D", "0E", "0F"
	db	"10", "11", "12", "13", "14", "15", "16", "17"
	db	"18", "19", "1A", "1B", "1C", "1D", "1E", "1F"
	db	"20", "21", "22", "23", "24", "25", "26", "27"
	db	"28", "29", "2A", "2B", "2C", "2D", "2E", "2F"
	db	"30", "31", "32", "33", "34", "35", "36", "37"
	db	"38", "39", "3A", "3B", "3C", "3D", "3E", "3F"
	db	"40", "41", "42", "43", "44", "45", "46", "47"
	db	"48", "49", "4A", "4B", "4C", "4D", "4E", "4F"
	db	"50", "51", "52", "53", "54", "55", "56", "57"
	db	"58", "59", "5A", "5B", "5C", "5D", "5E", "5F"
	db	"60", "61", "62", "63", "64", "65", "66", "67"
	db	"68", "69", "6A", "6B", "6C", "6D", "6E", "6F"
	db	"70", "71", "72", "73", "74", "75", "76", "77"
	db	"78", "79", "7A", "7B", "7C", "7D", "7E", "7F"
	db	"80", "81", "82", "83", "84", "85", "86", "87"
	db	"88", "89", "8A", "8B", "8C", "8D", "8E", "8F"
	db	"90", "91", "92", "93", "94", "95", "96", "97"
	db	"98", "99", "9A", "9B", "9C", "9D", "9E", "9F"
	db	"A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7"
	db	"A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF"
	db	"B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7"
	db	"B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF"
	db	"C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7"
	db	"C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF"
	db	"D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7"
	db	"D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF"
	db	"E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7"
	db	"E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF"
	db	"F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7"
	db	"F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF"


Using this code, one can get a pointer to the string representing the hexadecimal value in, for example, al:

       mov     al, someValue
       mov     bl, al                  ;bl contains the same value                                                                          
       and     ebx, 0x000000ff         ;extend bl into ebx                                                                                  
       shl     ebx, 1                  ;multiply ebx by 2 (because the table is a table of words)
       lea     ecx, [ebx+table]        ;Load Effective Address ebx+table in ecx
       mov     eax, 4
       mov     ebx, 1
       mov     edx, 2		        ;get ready to print 2 chars
       int     0x80			;print them

Problem 2


;;; 10/31/2012
;;; hw7b.asm
;;; Yoshie Sasaki (edited by D. Thiebaut)
;;;
;;; This program takes a string of bytes where two characters have been
;;; packed in each byte.  The first nybble (high) represents the lower
;;; nybble of an uppercase ascii.  Similarly for the second (low) nybble.
;;; Only ascii chars between '@' and 'O' can be represented that way
;;; (@, A, B, C, D, E, F, G, H, I, J, K, L, M, N, O)
;;; 	l
;;; Hexidecimal numbers 4 in the upper nibble represents chars "@ and
;;; A-O" in Ascii Code. If we want to just use these chars, memory
;;; can be saved. The data section can hold the lower nibbles, and the 
;;; fixed upper nibble can be accounted for in the code/text section. 
;;; The program connects the lower nibbles to the fixed upper to
;;; print the desired Ascii chars. A function is used to print the contents
;;; of each byte in memory. Strings from address "y" and "z" is printed.
;;;
;;; Example:
;;; yLen     dd     18
;;; y        db     0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
;;;          db     0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
;;;
;;; get decoded as
;;; MEED  CANDID OBAMA AND BONI OF GANA
;;;
;;; To Link and Run:
;;;   nasm -f elf -F stabs hw7b.asm
;;;   gcc -m32 -o hw7b driver.c asm_io.o hw7b.o
;;;   ./hw7b
 
                 %include "asm_io.inc"
 
             ;; -------------------------
             ;; data segment
             ;; -------------------------
             section .data
yLen     dd     18
y        db     0xd5, 0x54, 0x00, 0x31, 0xe4, 0x94, 0x0f, 0x21, 0xd1
         db     0x01, 0xe4, 0x02, 0xfe, 0x90, 0xf6, 0x07, 0x1e, 0x10
 
zLen     dd     24
z        db     0xef, 0x07, 0xff, 0x40, 0xd1, 0x41, 0xd5, 0x03, 0x81 
         db     0xee, 0x5c, 0x01, 0xe4, 0x02, 0x14, 0x0d, 0x1e, 0x0d
         db     0xf1, 0xe0, 0x9e, 0x0c, 0x9d, 0x10

             ;; -------------------------
             ;; code area
             ;; -------------------------
             section .text
             global  asm_main
asm_main:
;;; 
;;; ---  Decode y string ---
;;; 
             mov eax, 0
             mov ecx, dword[yLen] ;save memory length
             mov edx, y
	
             ;Go through bytes in memory & print char A to O
fory:        call printByte
             inc edx             ;inc byte count
             loop fory
             call print_nl

;;;
;;; --- Decode z string ---
;;; 

             mov eax, 0
             mov ecx, dword[zLen];save memory length
             mov edx, z
	
             ;Go through bytes in memory & print char A to O
forz:        call printByte
             inc edx             ;inc byte count
             loop forz
             call print_nl

;;;
;;; --- END (return to C program)
;;;
        ret

;;; -------------------------------------------------------------
;;;  PrintByte(As in the contents of the byte in memory)
printByte:   mov al, byte[edx]   ;Get next byte
	
;;;  print upper nybble...
             ror al, 4           ;Rotate the upper half down
             and al, 0x0F        ;Hide the rest
             add al, 0x40        ;Fill the top half with set Hex val
             cmp al, 0x40
             jne  noSpaceU       ;Skip next step if not "@"
	
             mov al, ' '         ;Else, "@" = " "
	
noSpaceU:    call print_char

;;;  print lower nybble...
             mov al, byte[edx]   ;Get byte again(Now looking at lower)
             and al, 0x0F        ;Do the same as upper half
             add al, 0x40        
             cmp al, 0x40
             jne  noSpaceL
             mov al, ' '
	
noSpaceL:    call print_char 
             ret