Page 1 of 1

Hello World program and questions about 2SIO output ready?

Posted: April 26th, 2021, 11:26 am
by wearwolf
I've been working through a bunch of test programs to learn more about the Altair 8800 and the 8080 instruction set. I was working on one program to print a null-terminated string when I realized it could be turned into a hello world example. That's where you are supposed to start with any new programming environment right? So here's my take on a Hello World program for the Altair 8800.

This was all hand assembled to the listing may not be properly formatted

Code: Select all

0000						  ORG 0
0000	3E 03				MVI A, 03H	;Rest 2SIO port
0002	D3 10				OUT 10H	
0004	3E 15				MVI A, 15H	;Set 2SIO port to 8n1
0006	D3 10				OUT 10H
0008	21 FE 00			LXI H, MSG	;Load message address
000B	DB 10	CHECK:	IN 10H		;Check 2SIO output ready
000D	E6 02				ANI 02H
000F	CA 0B 00			JZ CHECK
0012	7E					MOV A, M	;Load character
0013	FE 00				CPI 00H		;Check if null found
0015	CA 1E 00			JZ END
0018	D3 11				OUT 11H		;Ouput character
001A	23					INX H		;Move to next character
001B	C3 0B 00			JMP CHECK
001E	76		END:	  HLT

00FE	48 65 6C 6C		MSG:	Hell
0102	6F 2C 20 77				o, W
0106	6F 72 6C 64				orld
010A	21 0D 0A 00				!\r\n\0
I put the message at 00FE because I wanted it to go over the 1-byte address boundary to make sure it was incrementing the address correctly. Before I found the INX instruction I was thinking I was going to need to do a multi-byte add so I wanted to make sure that worked correctly when crossing that boundary.

Now my question is about this loop.

Code: Select all

CHECK:	IN 10H
		   ANI 02H
		   JZ CHECK
During an earlier test I was printing a CR and a LF character right after each other and it seemed like sometimes it worked and sometimes output would get missed/muddled. So I added this loop to check that the Transmit Data Register Empty flag is set before outputting a value.

My questions are
1. Is there a better way to check if output is ready? (I figure this has been done enough that people have likely found the best way to do it)
2. Are there any guidelines on when the output ready check is needed?

Re: Hello World program and questions about 2SIO output read

Posted: April 26th, 2021, 4:41 pm
by TronDD
There are smarter people here than I, but that's basically how to do the check. You could also RRC twice and JNC. Not sure the time difference between two RRC instructions and one ANI.

You should always do the check. The CPU is much faster than a 9600 baud UART.

Fun exercise. Put a counter in the loop and see how many times it has to check between sending 2 characters.

Re: Hello World program and questions about 2SIO output read

Posted: May 29th, 2021, 11:52 am
by wearwolf
According to the 8080/8085 Assembly Language Programming manual an ANI instruction takes 7 states and the rotate instructions each take 4 states. So ANI is probably slightly faster but not by much. Both take up two bytes so there's no memory difference.

I tested the number of retries using this program.

Code: Select all

0000                     ORG 0
0000   3E 03             MVI A, 03H   ;Reset 2SIO port
0002   D3 10             OUT 10H
0004   3E 15             MVI A, 15H   ;Set 2SIO to 8n1
0006   D3 10             OUT 10H
0008   21 30 00          LXI H, 0030H ;Init output address
000B   06 00     LOOP:   MVI B, 00H   ;clear B
000D   3E 30             MVI A, 30H   ;set A = '0'
000F   D3 11             OUT 11H      ;output '0'
0011   DB 10      CHK:   IN 10H       ;read status byte
0013   04                INR B        ;increment B
0014   E6 02             ANI 02H      ;Check output ready
0016   CA 11 00          JZ CHK
0019   7D                MOV M, B     ;Write B to memory
001A   23                INX H        ;increment memory address
001B   C3 0B 00          JMP LOOP
Strangely the first character only goes through the loop once before the output is clear but all subsequent sends go through 60 or 61 times. So I guess the output check is much more important if you're going to be sending a lot of characters at once and less important if you are only sending one character occasionally.

Re: Hello World program and questions about 2SIO output read

Posted: May 29th, 2021, 4:59 pm
by AltairClone
The UART has the data register you actually write to and then a separate shift register that is used while the character is being serially transmitted. When the UART has been idle for at least two character times, then both registers are empty. A write to the data register is immediately transferred to the shift register for transmission. At this point, the data register is empty again and shows “ready” as soon as your software checks again. When you write the second character to the data register, that byte now has to remain in the data register until the 1st character is out of the shift register (about one character time at the chosen baud rate). From then on, until there is a pause in the output data, it will always take a character time until the UART shows ready for another character.

Mike

Re: Hello World program and questions about 2SIO output read

Posted: May 29th, 2021, 5:06 pm
by TronDD
wearwolf wrote: Strangely the first character only goes through the loop once
Well, you just initialized everything so the UART and line are clear.
less important if you are only sending one character occasionally.
Well, "occasionally" is a bit squishy. If you send 1 character, go do some other stuff, then send 1 more character, you still should check to be sure because 61 loops of 4 instructions is quite a lot of stuff you can do. And that's not accounting for RTS possibly halting the transfer for an unknown length of time.

Re: Hello World program and questions about 2SIO output read

Posted: June 2nd, 2021, 12:32 pm
by wearwolf
TronDD wrote:
wearwolf wrote: Strangely the first character only goes through the loop once
Well, you just initialized everything so the UART and line are clear.
I mean after you sent the first byte it immediately shows as empty. Unless you are saying there's some kind of pipelining going on where the first byte moves into the sending circuitry which frees up the buffer for the next byte.

And yeah building a full program you'd always want to have the check just to be safe. I was more thinking for testing it's useful to know when you can get away without including the check. Saving yourself having to enter in those 7 bytes.