I created the following file:
% msx() { printf '10 ? "HELLO"\r\n20 GOTO 10\r\n\x1a' >! msx.bas }
% msx
% cat -v msx.bas
10 ? "HELLO"^M
20 GOTO 10^M
^Z
% hexdump -C msx.bas
00000000 31 30 20 3f 20 22 48 45 4c 4c 4f 22 0d 0a 32 30 |10 ? "HELLO"..20|
00000010 20 47 4f 54 4f 20 31 30 0d 0a 1a | GOTO 10...|
This uses CRLF as line endings (0x0d 0x0a), including one at the end, and then follows with a 0x1a at the end of the file. So far so good.
I tried to use the 'binary' option:
% msx && vim --clean +'set binary' +wq msx.bas && hexdump -C msx.bas
00000000 31 30 20 3f 20 22 48 45 4c 4c 4f 22 0a 32 30 20 |10 ? "HELLO".20 |
00000010 47 4f 54 4f 20 31 30 0a |GOTO 10.|
Converts to Unix and drops EOL; this is documented in :help 'binary':
'fileformat' and 'fileformats' options will not be used, the file is read and written like 'fileformat' was "unix" (a single <NL> separates lines).
So that's not very "binary", but okay.
With 'fileformats' and 'noendofline' I get the behaviour you're seeing:
% msx && vim --clean +'set noendofline fileformat=dos' +wq msx.bas && hexdump -C msx.bas
% msx && vim --clean +'set noendofline fileformats=dos fileformat=dos' +wq msx.bas && hexdump -C msx.bas
00000000 31 30 20 3f 20 22 48 45 4c 4c 4f 22 0d 0a 32 30 |10 ? "HELLO"..20|
00000010 20 47 4f 54 4f 20 31 30 0d 0a | GOTO 10..|
It retains DOS line endings and drops ^Z.
I tried the 'nofixendofline' option:
% msx && vim --clean +'set noendofline nofixendofline fileformats=dos fileformat=dos' +wq msx.bas && hexdump -C msx.bas
00000000 31 30 20 3f 20 22 48 45 4c 4c 4f 22 0d 0a 32 30 |10 ? "HELLO"..20|
00000010 20 47 4f 54 4f 20 31 30 | GOTO 10|
And that drops the trailing EOL and ^Z.
So ... I don't know. I don't think Vim can do this. It seems to drop the ^Z when reading the file, because I don't see it after opening it.