Z80 Programming VI-a |
UART Terminal String and Echo Test |
Page a Page b |
New Functions: We have moved further into the .asm file. We have created 5 new functions after the starting point of "START and ECHO". They are: - UART_PRNT_STR - UART_TX_READY - UART_TX - UART_RX_READY - UART_RX
Each function/procedure has its own commented name and function description in the adjacent screenshot. A blank line separates the function from whatever follows that chunk of code. This lends to the function's appearance of modularity. Why do we say we are "calling" these functions? Because they can be "CALLed" by their label name, and they "RETurn" to the line following the CALL when completed. For example, line 57 reads "CALL UART_PRNT_STR". We can see that label at the beginning of line 68. There are several lines in the code, including another CALL at line 74, and then finally the RET in line 79. When a CALL is RETurned, it is always to the line following the matching CALL.
Let's have a brief look at this function. Note that we will be jumping around a little bit. The numbered arrows should help you from getting lost. - Line 57 calls line 68. Code runs and then... - Line 74 calls line 98. - Line 99 calls line 85. Code runs and then... - Line 92 returns to line 100, code runs and then... - Line 101 returns to line 75, code runs and then... - Line 79 returns to the code following line 57 which started this cascade of calls
What is all of this code doing? According to the comments in line 52, it's going to print a string to the terminal screen, then switch over to echoing every user key press. We're just looking at the string printing part for now. The call to UART_PRNT_STR in line 57 only used the UART_TX function to send data. It did not use the UART_RX function to read the user key presses: that occurs later.
Due to the limit of my editing tools, I have placed the bottom part of the .asm file after the top part. Hopefully it displays as such on your screen. If not, you can use good ole Programmer's Notebook (PN) to open the RS232_String_Echo.asm file and navigate to the end to see the whole thing.
When UART_PRNT_STR in CALLed in line 57, it's because the address of label "RS232_Echo" was placed in the "HL" register pair in line 56. (Also, A is cleared for "safety" reasons.) The label can be found in line 126. There is an assembler directive to treat what follows ".DB" in quotation marks as data bytes. We see the string "RS232 Test" followed by Carriage Return ($0D) and Line Feed ($0A). At the end is the byte "$00". This is a commonly used "End Of String" or EOS marker that tells the CALLed routine when there is no more data to display or process or whatever.
So when UART_PRNT_STR is called in line 57, it's already pointing to the string to be "printed" or displayed. Each byte in the string will be displayed. To do so, the program will check if the UART is ready to send and that starts in line 71 shortly after the current contents of the AF register pair are pushed onto the stack in line 69. We can ignore line 70 for just a moment. The "LD A, (HL)" of line 71 reads "Take the contents of the address pointed to by the HL register pair and copy it into register A." Note that I said "contents". That is what is meant when you see the parentheses, "()", surrounding the register pair, HL. Line 72 reads "ComPare the contents in register A with the EOS character defined in line 20 as '$00'. If 'A - EOS' is equal to zero, then set the Zero flag." The first character in the string discussed earlier is the letter "R"; it is not zero. In fact, it's ASCII value is $52, so "$52 - $00" is a positive number; it is not 0. The ComPare fails because we have not come to the end of the string; we're just at the beginning. Thus the "JP Z..." that follows in line 73 will not succeed and execution will fall through to line 74.
Line 74 contains another call but to the label "UART_TX"; it seems we have a character, the letter "R", to print/send to the terminal display. When the first call occurred in line 57, the address of the instruction that followed it was pushed onto the stack. We would have to look at the .lst file to know what that is. (I just checked and it's address $001B.) Now that another call is about to occur in line 74, the address of the instruction at line 75 needs to be put on the stack, too. So when the RETurn for this call occurs, execution can resume at line 75 (address $002E). Let's keep going.
Before the character "R" can be printed to the terminal screen, the UART has to be ready. The call to line 98 from line 74 invokes another call in line 99 to label UART_TX_RDY. When we navigate to it in line 85, AF is preserved again on the stack in line 86 and then we test the UART for readiness. This is done by copying the contents of the LCR or UART5 to register A in line 88. We then test bit 5 of that byte. If the bit is a zero, then the UART is not ready to send and we jump to line 87 where we see the label UART_TX_RDY_LP. It's a LooP as you no doubt guessed and that's where we stay, continually testing to see if bit 5 of the LCR byte is a one. If it is a one, then we restore the AF register pair by popping it off the stack in line 91. Line 92 is a RETurn to line 100 which followed our last CALL. Line 100 reads "Take the letter R that I saved on the stack earlier and send it to UART0, the THRE buffer, so it can be sent bit by bit to the terminal." The RETurn in line 101 (arrow 8) takes us to line 75 that followed the previous CALL. Here HL is incremented to point to the next byte in the string, the letter "S". Immediately following in line 76 is an instruction to jump to the transmit loop in line 70, as you can seen in the comments section. In the loop we can see the next character is loaded into HL, checked that it's not "EOS", function "UART_TX" is called, the UART is checked if it's ready to send, and then the letter "S" with ASCII value "$53" is sent in binary as "0101 0011" onto the wire by the UART. This process continues until finally the value $00 or EOS is read; it's the last byte in the RS232_Echo string. If it succeeds, then a jump is made in line 73 to line 78. The original value of "AF" is popped off the stack and a RETurn to the first calling function is made in line 79. That return is to line 59, our next interesting but shorter discussion. |