8.13. DEMOS
The interrupts are enabled back with thePOPFinstruction, which restores theIFflag as well.
It is not possible to use theINinstruction with registers other thanAL, hence the shuffling.
My attempt to reduce Trixter’s version: 27 bytes
We can say that since we use the timer not to get a precise time value, but a pseudo-random one, we do
not need to spend time (and code) to disable the interrupts.
Another thing we can say is that we need only one bit from the low 8-bit part, so let’s read only it.
We can reduced the code slightly and we’ve got 27 bytes:
00000000: B9D007 mov cx,007D0 ; limit output to 2000 characters
00000003: 31C0 xor ax,ax ; command to timer chip
00000005: E643 out 043,al
00000007: E440 in al,040 ; read 8-bit of timer
00000009: D1E8 shr ax,1 ; get second bit to CF flag
0000000B: D1E8 shr ax,1
0000000D: B05C mov al,05C ; prepare '\'
0000000F: 7202 jc 000000013
00000011: B02F mov al,02F ; prepare '/'
; output character to screen
00000013: B40E mov ah,00E
00000015: CD10 int 010
00000017: E2EA loop 000000003
; exit to DOS
00000019: CD20 int 020
Taking random memory garbage as a source of randomness
Since it is MS-DOS, there is no memory protection at all, we can read from whatever address we want.
Even more than that: a simpleLODSBinstruction reads a byte from theDS:SIaddress, but it’s not a
problem if the registers’ values are not set up, let it read 1) random bytes; 2) from a random place in
memory!
It is suggested in Trixter’s webpage^48 to useLODSBwithout any setup.
It is also suggested that theSCASB
instruction can be used instead, because it sets a flag according to the byte it reads.
AnotherideatominimizethecodeistousetheINT 29hDOSsyscall, whichjustprintsthecharacterstored
in theALregister.
That is what Peter Ferrie and Andrey “herm1t” Baranovich did (11 and 10 bytes)^49 :
Listing 8.22: Andrey “herm1t” Baranovich: 11 bytes
00000000: B05C mov al,05C ;'\'
; read AL byte from random place of memory
00000002: AE scasb
; PF = parity (AL - random_memory_byte) = parity (5Ch - random_memory_byte)
00000003: 7A02 jp 000000007
00000005: B02F mov al,02F ;'/'
00000007: CD29 int 029 ; output AL to screen
00000009: EBF5 jmp 000000000 ; loop endlessly
SCASBalso uses the value in theALregister, it subtract a random memory byte’s value from the5Ch
value inAL.JPis a rare instruction, here it used for checking the parity flag (PF), which is generated by
the formulae in the listing. As a consequence, the output character is determined not by some bit in a
random memory byte, but by a sum of bits, this (hopefully) makes the result more distributed.
It is possible to make this even shorter by using the undocumented x86 instructionSALC(AKASETALC)
(“Set AL CF”). It was introduced in the NEC V20CPUand setsALto0xFFifCFis 1 or to 0 if otherwise.
(^48) http://go.yurichev.com/17305
(^49) http://go.yurichev.com/17087