I use EdSim51 emulator (for 8051 MCU), following this notes. I wrote a program that sends data, but sometimes (not always) it sends garbage.
JMP main
ORG 23h ; serial interrupt vector
JBC TI,sendString
RETI
ORG 30h
str: DB 'H','e','l','l','o',0Dh,0
sendString:
CLR A
MOVC A,@A+DPTR ; read next char from str
INC DPTR
JZ sendStringEnd ; if the char is not 0
MOV SBUF,A ; write next char
sendStringEnd:
RETI
main:
CLR SM0
SETB SM1 ; serial mode 1
MOV TMOD,#20h
MOV TH1,#243
MOV TL1,#243
SETB TR1 ; 2400 baud rate
SETB EA
SETB ES ; enable serial interrupt
MOV DPTR,#str ; DPTR points to Hello string
SETB TI ; force interrupt
JMP $
MOV SBUF,A writes correct data to SBUF, but serial monitor shows garbage, see the image.

Looks like the baud rate is not synchronized. Or did I forget something? What is the source of the messed output?
You forgot to clear TI at the end of the ISR. Because the serial port's two interrupt sources (transmit and receive) share one vector, neither TI nor RI are cleared by the hardware upon vectoring. It is up to the programmer to do so.
James Rogers - EdSim51 Creator