Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

FizzBuzz

290 views
Skip to first unread message

Frank Kotler

unread,
Apr 11, 2016, 7:59:20 AM4/11/16
to
Ooops! Got fumble-fingered and almost accidentally rejected this one,
but fished it out of the bin. This is from Mike Gonta, not me. Sorry Mike!

Best,
Frank


Here is a simple "freestanding" PM32 classic mode version of
FizzBuzz. https://en.wikipedia.org/wiki/Fizz_buzz
"Fizz buzz has been used as an interview screening device
for computer programmers. Creating a list of the first 100
Fizz buzz numbers is a trivial problem for any would-be
computer programmer, so interviewers can easily sort out
those with insufficient programming ability."
Note: "real programmers" use hexadecimal notation and
assembly language.
Assemble with NASM or FASM.

<code>
org 0x400000
use32
FIZZBUZZ:
mov ecx, 1
mov ebp, 3
mov edi, 5
cld
start:
mov eax, ecx
xor edx, edx
div ebp
mov ebx, edx
mov eax, ecx
xor edx, edx
div edi
test ebx, ebx
jne .2
test edx, edx
jne .1
mov esi, FizzBuzz
call print_string
jmp again
..1:
mov esi, Fizz
call print_string
jmp again
..2:
test edx, edx
jne .3
mov esi, Buzz
call print_string
jmp again
..3:
mov eax, ecx
call print_hex
again:
lea ecx, [ecx+1]
cmp ecx, 100
ja exit
mov esi, comma
call print_string
jmp start
exit:
mov eax, 0
int 0x16
ret

print_hex:
pusha
mov edx, eax
mov ah, 0xE
xor ebx, ebx
mov esi, hex
call print_string
mov ecx, 2
..1:
rol dl, 4
mov al, dl
and al, 0xF
add al, '0'
cmp al, '9'
jbe .2
add al, 'A'-('9'+1)
..2:
int 0x10
sub ecx, 1
jne .1
popa
ret

print_string:
pusha
mov ah, 0xE
xor bh, bh
..1:
lodsb
test al, al
je .2
int 0x10
jmp .1
..2:
popa
ret

FizzBuzz: db "FizzBuzz", 0
Fizz: db "Fizz", 0
Buzz: db "Buzz", 0
hex: db "0x", 0
comma: db ", ", 0
</code>


Mike Gonta
look and see - many look but few see

http://mikegonta.com
http://tawk.to/mikegonta

Mike Gonta

unread,
Apr 11, 2016, 8:46:37 AM4/11/16
to
"Frank Kotler" wrote:
> Ooops! Got fumble-fingered and almost accidentally
> rejected this one, but fished it out of the bin. This is
> from Mike Gonta, not me. Sorry Mike!

No problem Frank.
I also believe in giving credit where credit is due.
http://forum.osdev.org/viewtopic.php?f=2&t=30280

Mike Gonta

unread,
Apr 11, 2016, 8:46:48 AM4/11/16
to
"Frank Kotler" wrote:
> Ooops! Got fumble-fingered and almost accidentally
> rejected this one, but fished it out of the bin. This is
> from Mike Gonta, not me. Sorry Mike!

> <code>
> ....
> jne .2
> test edx, edx
> jne .1
> mov esi, FizzBuzz
> call print_string
> jmp again
> ..1:
> mov esi, Fizz
> call print_string
> jmp again
> ..2:
> ....

Seems like "fishing" adds an extra dot where it should't be.

R.Wieser

unread,
Apr 11, 2016, 9:32:19 AM4/11/16
to
Mike,

Alas, the definition from that wiki is impossible to follow ....

[quote]
... replacing any number divisible by three with the word "fizz", and any
number divisible by five with the word "buzz".
[/quote]

As far as I know it you can *replace* something with anything, but not with
multiple anythings at the same time.

In short, although the origional problem intended to sometimes have *both*
words printed instead of the value the above either is insolvable, or allows
the word "buzz" to *override* "fizz".

Yes, explaining/defining a problem is hard. Often much harder than writing
a program. :-)


As for the program itself ? It doesn't look too bad. Apart from not
having any kind of documentation ofcourse. Personally I would not grade it
too high though. A "print_hex" routine which is provided a 32-bit value,
but only displays two digits ? Displaying a single character comma using
"print_string" ? Using two registers to remember the 3 and 5 divisors as
well as using "div" (hint: idiv)? Assuming that registers like EDX and
ECX will *not* get clobbered by an INT 10h (print_hex) and assuming that AH
will not get clobbered by it either (print_string) ?

Either you're very lucky, or you have not tested that code ...


Also, what is your affection with ridicilously high (and presumably
non-relocatable) ORGs ? What happens when someones computer already uses
that bit of memory for something else ?

Regards,
Rudy Wieser


-- Origional message:

Melzzzzz

unread,
Apr 11, 2016, 10:32:33 AM4/11/16
to
Here is my avx2 version of fizzbuzz ;)

format elf64 executable 3
include 'import64.inc'

interpreter '/lib64/ld-linux-x86-64.so.2'
needed 'libc.so.6'
import exit,printf

segment executable
entry $
xor ebx,ebx
.L0:
vpmovzxdq ymm0,[arr+ebx] ; zero extend to quad word
vpmuludq ymm1,ymm0,yword[cnst3] ; division by multiply and shift
vpsrlq ymm2,ymm1,33
vpmuludq ymm3,ymm2,yword[three] ; multiply
vpcmpeqd ymm4,ymm0,ymm3 ; see difference
vpaddd ymm4,ymm0,ymm4 ; add resulting mask which is -1 if equal
vpshufb ymm4,ymm4,yword[smask] ; mov dwords in right place
vpermq ymm4,ymm4,1000b ; mov 4 dwords in place

vpmuludq ymm1,ymm0,yword[cnst5]
vpsrlq ymm2,ymm1,34
vpmuludq ymm3,ymm2,yword[five]
vpcmpeqd ymm5,ymm0,ymm3
vpaddd ymm5,ymm5,ymm5 ; make that in -2
vpshufb ymm5,ymm5,yword[smask]
vpermq ymm5,ymm5,1000b

vpaddd ymm4,ymm5,ymm4 ; if both matches then -3 would be added

vmovdqa [arr+ebx],xmm4
add ebx,16
cmp ebx,100*4
jl .L0
xor ebx,ebx
.L1:
mov r8,fizzbuzz
mov r9,fizz
mov r10,buzz
mov edx,[arr+rbx*4]
lea esi,[rbx+1]
mov rdi,fmt
sub esi,edx
cmp esi,3 ; if difference is 3 then both matches
cmove rdi,r8
cmp esi,2 ; buzz matches
cmove rdi,r10
cmp esi,1 ; fizz matches
cmove rdi,r9
lea rsi,[rbx+1]
xor eax,eax
call [printf]
inc ebx
cmp ebx,100
jl .L1
xor edi,edi
.exit:
call [exit]

segment writeable
align 16
arr: times 100 dd % ; initialize 1..100
align 32
cnst3 dq 4 dup(2863311531) ; required shift 33
three dq 4 dup(3)
cnst5 dq 4 dup(3435973837) ; required shift 34
five dq 4 dup(5)
smask db 0,1,2,3
db 8,9,10,11
times 4 db -128
times 4 db -128
db 0,1,2,3
db 8,9,10,11
times 4 db -128
times 4 db -128

fmt db '%4d %d',0xa,0
fizz db '%4d fizz',0xa,0
buzz db '%4d buzz',0xa,0
fizzbuzz db '%4d fizzbuzz',0xa,0

Mike Gonta

unread,
Apr 11, 2016, 11:02:39 AM4/11/16
to
"R.Wieser" wrote:
> Mike,
>
> Alas, the definition from that wiki is impossible to
> follow ....
> [quote]
> ... replacing any number divisible by three with the word
> "fizz", and any number divisible by five with the word
> "buzz".
> [/quote]

Did I forget to mention that understanding the criteria
(something that apparently even children can do) is part of
the test.
[quote}
Fizz buzz is a group word game for children to teach them
about division. Players take turns to count incrementally,
replacing any number divisible by three with the word
"fizz", and any number divisible by five with the word
"buzz".
[/quote]

> As far as I know it you can *replace* something with
> anything, but not with multiple anythings at the same
> time.
>
> In short, although the origional problem intended to
> sometimes have *both* words printed instead of the value
> the above either is insolvable, or allows the word "buzz"
> to *override* "fizz".

Ok, you've confused me (or should I say) convinced me
- you're not hired.

> Yes, explaining/defining a problem is hard. Often much
> harder than writing a program. :-)
> As for the program itself ? It doesn't look too bad.
> Apart from not having any kind of documentation ofcourse.
> Personally I would not grade it too high though.

Please keep in mind that it I who am grading you.

> A "print_hex" routine which is provided a 32-bit value,
> but only displays two digits ?

It's simply my "cut & paste" routine - the numbers are no
larger than 0x64 and the original routine displays 8 digits
otherwise.

> Displaying a single character comma using "print_string" ?

Had I coded it inline, your complaint would have been "much
code refactoring is necessary".

> Using two registers to remember the 3 and 5 divisors as
> well as using "div" (hint: idiv)?

If I don't put them in available registers, they have to go
in memory - there is no such thing as "IDIV 3".

> Assuming that registers like EDX and ECX will *not* get
> clobbered by an INT 10h (print_hex) and assuming that AH
> will not get clobbered by it either (print_string) ?

That's a perfectly valid point. I can afford to be lazy.
SudoBIOS (while providing full access to the native
motherboard BIOS) guarantees that only those registers and
flags that return values are modified. This is based on the
"standard" BIOS function API as documented by RBIL and the
SudoBIOS source code.

> Either you're very lucky, or you have not tested that code

Both, and fully tested (by me of course), obviously someone
here is talking through their (non-programmer) hat.

> Also, what is your affection with ridicilously high
> (and presumably non-relocatable) ORGs ? What happens when
> someones computer already uses that bit of memory for
> something else ?

This is (as I stated in the original opening) - 32 bit
protected mode Classic Mode code. It uses the native
motherboard BIOS while running in PM32 from high memory.
Obviously, it is a place that some have not yet gone.
For the faint of heart the code is easily converted to
16 bit real mode (a place that I luckily (as you previously
surmised) no longer have to go to.

Mike Gonta

unread,
Apr 11, 2016, 11:17:42 AM4/11/16
to
"Melzzzzz" wrote:
> On Mon, 11 Apr 2016 08:00:16 -0400
> Frank Kotler <fbko...@nospicedham.myfairpoint.net> wrote:
>
>> Ooops! Got fumble-fingered and almost accidentally
>> rejected this one, but fished it out of the bin. This is
>> from Mike Gonta, not me. Sorry Mike!

>> Here is a simple "freestanding" PM32 classic mode version
>> of FizzBuzz. https://en.wikipedia.org/wiki/Fizz_buzz
>> "Fizz buzz has been used as an interview screening device
>> for computer programmers. Creating a list of the first 100
>> Fizz buzz numbers is a trivial problem for any would-be
>> computer programmer, so interviewers can easily sort out
>> those with insufficient programming ability."
>> Note: "real programmers" use hexadecimal notation and
>> assembly language.

> Here is my avx2 version of fizzbuzz ;)

Very good. Too complicated for me. Obviously, we won't be
able to hire you, you'll probably expect too high a salary.
How about a screen shot so that we can verify that it works?
Mine is here:
http://forum.osdev.org/viewtopic.php?f=2&t=30280

Melzzzzz

unread,
Apr 11, 2016, 12:02:54 PM4/11/16
to
[bmaxa@maxa-pc tasks]$ fasm fizzbuzz.asm
flat assembler version 1.71.51 (16384 kilobytes memory)
3 passes, 1546 bytes.
[bmaxa@maxa-pc tasks]$ ./fizzbuzz
1 1
2 2
3 fizz
4 4
5 buzz
6 fizz
7 7
8 8
9 fizz
10 buzz
11 11
12 fizz
13 13
14 14
15 fizzbuzz
16 16
17 17
18 fizz
19 19
20 buzz
21 fizz
22 22
23 23
24 fizz
25 buzz
26 26
27 fizz
28 28
29 29
30 fizzbuzz
31 31
32 32
33 fizz
34 34
35 buzz
36 fizz
37 37
38 38
39 fizz
40 buzz
41 41
42 fizz
43 43
44 44
45 fizzbuzz
46 46
47 47
48 fizz
49 49
50 buzz
51 fizz
52 52
53 53
54 fizz
55 buzz
56 56
57 fizz
58 58
59 59
60 fizzbuzz
61 61
62 62
63 fizz
64 64
65 buzz
66 fizz
67 67
68 68
69 fizz
70 buzz
71 71
72 fizz
73 73
74 74
75 fizzbuzz
76 76
77 77
78 fizz
79 79
80 buzz
81 fizz
82 82
83 83
84 fizz
85 buzz
86 86
87 fizz
88 88
89 89
90 fizzbuzz
91 91
92 92
93 fizz
94 94
95 buzz
96 fizz
97 97
98 98
99 fizz
100 buzz

Kerr Mudd-John

unread,
Apr 11, 2016, 12:17:58 PM4/11/16
to
On Mon, 11 Apr 2016 15:58:10 +0100, Mike Gonta
<mike...@nospicedham.gmail.com> wrote:

[]
> For the faint of heart the code is easily converted to
> 16 bit real mode (a place that I luckily (as you previously
> surmised) no longer have to go to.
>
Pah 8 bit roolz!

http://rosettacode.org/wiki/FizzBuzz/Assembly

(google search beats hand-coding my own solution, call me lazy)

Oh alright, here's something I wrote earlier; 30 odd years earlier!

(Note the stolen print routine with caps and lcase intermixed!)

[Masm]

Title FizzBuzz
code segment
.radix 16
org 100
include stdequ.inc
;include stdmcr.inc

assume cs:code,ds:code
;;Main

xor cx,cx ; total count
mov bh,0 ; threes
mov bl,0 ; fives
eachnum:
inc bh
inc bl
inc cx
xor si,si ; printed flag
cmp bh,3
jne not3
mov bh,0
mov dx,offset Fizz
call dos_prtstrg
inc si
not3:
cmp bl,5
jne not5
mov bl,0
mov dx,offset Buzz
call dos_prtstrg
inc si
not5:
cmp si,0
jnz dunprint
; else print num
mov ax,cx
push bx
mov bx,10d
call prt_dec
pop bx
dunprint:
mov dx,offset crlf
call dos_prtstrg
cmp cx,100d
jl eachnum

;; End Prog
ret

crlf db cr,lf,eos

Fizz db "Fizz",eos
Buzz db "Buzz",eos

dos_prtstrg proc near
mov ah,9
int 21
ret
dos_prtstrg endp

prt_dec proc near
OR ax,ax ; anything left?
JZ pd1
xor dx,dx
DIV bX ; /10
PUSH dx ; add num to stack
CALL prt_dec ; recurse!

POP dX ; take from stack and prt
ADD dl,30h ; cvrt to disp num
mov ah,2
int 21
pd1:
RET

prt_dec endp


code ends


end

--
Bah, and indeed, Humbug

Robert Wessel

unread,
Apr 11, 2016, 12:48:15 PM4/11/16
to
On Mon, 11 Apr 2016 15:20:59 +0200, "R.Wieser"
<add...@nospicedham.not.available> wrote:

>Mike,
>
>Alas, the definition from that wiki is impossible to follow ....
>
>[quote]
>... replacing any number divisible by three with the word "fizz", and any
>number divisible by five with the word "buzz".
>[/quote]
>
>As far as I know it you can *replace* something with anything, but not with
>multiple anythings at the same time.
>
>In short, although the origional problem intended to sometimes have *both*
>words printed instead of the value the above either is insolvable, or allows
>the word "buzz" to *override* "fizz".
>
>Yes, explaining/defining a problem is hard. Often much harder than writing
>a program. :-)


The next, and immediately following, paragraph is "Players generally
sit in a circle. The player designated to go first says the number
"1", and each player thenceforth counts one number in turn. However,
any number divisible by three is replaced by the word fizz and any
divisible by five by the word buzz. Numbers divisible by both become
fizz buzz. A player who hesitates or makes a mistake is eliminated
from the game.", and then provides an example of the desired results.

Certatinly many programmers find *reading* specs to be hard too. Which
is also a problem worth testing for. ;-)

Mike Gonta

unread,
Apr 11, 2016, 12:48:18 PM4/11/16
to
"Kerr Mudd-John" wrote:
> Mike Gonta wrote:
>
> []
>> For the faint of heart the code is easily converted to
>> 16 bit real mode (a place that I luckily (as you previously
>> surmised) no longer have to go to.
>>
> Pah 8 bit roolz!

A place nobody can go.

> http://rosettacode.org/wiki/FizzBuzz/Assembly

[quote]
At least, I should point out that this program is a little
bugged ....
[/quote]

> Oh alright, here's something I wrote earlier; 30 odd years
> earlier!

Very good. We'll let you off the hook this time. 30 years
ago there was no better excuse than 16 bit real mode and DOS.

Terje Mathisen

unread,
Apr 11, 2016, 1:33:30 PM4/11/16
to
Perl is a very good language for these kinds of tex processing problems,
I wrote a version which also prints fizz/buzz for each 3/5 digit in the
number:

#!perl -w
use strict;
for (my $i = 1; $i < 100; $i++) {
my @out = ();
push(@out, "fizz") if ($i % 3 == 0);
push(@out, "buzz") if ($i % 5 == 0);
my $s = sprintf("%d", $i);
for (my $l = 0; $l < length($s); $l++) {
my $ch = substr($s, $l, 1);
push(@out, "fizz") if ($ch eq '3');
push(@out, "buzz") if ($ch eq '5');
}
push(@out, $s) if (scalar(@out) == 0);

printf("%4d: %s\n", $i, join(" ", @out));
}

The key here is that you should use tools that fit the task. :-)

Personally I love good asm code, but for the last 20 years I've tried to
not use asm for tasks where it isn't needed.

Terje

--
- <Terje.Mathisen at tmsw.no>
"almost all programming can be viewed as an exercise in caching"

Mike Gonta

unread,
Apr 11, 2016, 2:03:50 PM4/11/16
to
"Robert Wessel" wrote:
Hi Robert,

Finally, we are in agreement. However, please keep in mind
that the children's game is context and not the
specification. Hopefully when (according to Wikipedia) it
is/was used as employment screening criteria, the specs are
suitable for simple programming.

Mike Gonta

unread,
Apr 11, 2016, 2:03:57 PM4/11/16
to
"Terje Mathisen" wrote:
> Mike Gonta wrote:
>> "Frank Kotler" wrote:
>>> Ooops! Got fumble-fingered and almost accidentally
>>> rejected this one, but fished it out of the bin. This is
>>> from Mike Gonta, not me. Sorry Mike!
>>
>> No problem Frank.
>> I also believe in giving credit where credit is due.
>> http://forum.osdev.org/viewtopic.php?f=2&t=30280
>>
>>
>> Mike Gonta
>> look and see - many look but few see
>>
>> http://mikegonta.com
>> http://tawk.to/mikegonta
>>
>>
> Perl is a very good language for these kinds of tex
> processing problems, I wrote a version which also prints
> fizz/buzz for each 3/5 digit in the number:

Very good. I would like to say however, that the reason
someone "dug up" this oldie is to present a "freestanding
version" of which mine is also (as well asm). I'm the
thread starter, but not the instigator - who is here:
http://forum.osdev.org/viewtopic.php?f=2&t=30280
While on the subject, I would also like to point out that I
purposely linked my osdev comment back here. There is also a
reddit at: https://www.reddit.com/r/osdev/ looking for
upvotes - also to help boost the CLAX visitor count.

Bernhard Schornak

unread,
Apr 11, 2016, 3:50:04 PM4/11/16
to
You can omit the time consuming divisions if you compare EBP against
3 and EDI against 5. Jump to a label when equal and add 3 to EBP (or
5 to EDI), print the message and continue to compare against the new
multiple of 3 or 5. Actually, all multiples of 5 either end with a 0
or a 5, so you do not even need to add a separate counter, but check
if ECX is zero or five. This saves an entire register you might need
for the output routine.


Greetings from Augsburg

Bernhard Schornak

R.Wieser

unread,
Apr 11, 2016, 4:35:12 PM4/11/16
to
Robert,

> The next, and immediately following, paragraph is
[Snip]

So, we now have *two* explanations witch *differ* from each other. Yeah,
that really makes stuff easier. :-(

> Certatinly many programmers find *reading* specs to be hard too.
> Which is also a problem worth testing for. ;-)

Normally I stop when encountering the first sign that I have to second-guess
someones intentions. Most likely because making a "best choice" assumption
regulary resulted in that I could bin everything from that point on because
it was ment just a _little_ bit different. :-\

Regards,
Rudy Wieser


-- Origional message:
Robert Wessel <robert...@nospicedham.yahoo.com> schreef in berichtnieuws
flhngb9ih90skhp53...@4ax.com...

Frank Kotler

unread,
Apr 11, 2016, 5:05:19 PM4/11/16
to
Mike Gonta wrote:

...
> Seems like "fishing" adds an extra dot where it should't be.

Yeah, sorry 'bout that. I used to know why that happened - whose job it
was to add that extra dot and whose job it was to remove it. I forget
now. Used to happen quite a bit. Rather than worry about it, I'll just
try not to reject any "good" messages in the first place. I don't know
how I did that!

I am definitely not hired!

Best,
Frank

R.Wieser

unread,
Apr 11, 2016, 5:20:30 PM4/11/16
to
Mike,

> Did I forget to mention that understanding the criteria
> (something that apparently even children can do) is part
> of the test.

True. Thats why I made that remark: You, and probably many others, just
assumed it said what you already knew about FizzBuzz. Alas, it didn't.
:-)

> Ok, you've confused me (or should I say) convinced me
> - you're not hired.

Lol. Many people look, but few see.

Think about it: If you replace the milk thats in a glass with lemonade, can
you than at the same time replace it with rootbeer ? I for one don't
think that that is possible. Do you ?

> Please keep in mind that it I who am grading you.

Ofcourse. Thats why you posted your code for us to see, isn't it ?

> It's simply my "cut & paste" routine - the numbers are no
> larger than 0x64 and the original routine displays 8 digits
> otherwise.

Than its even worse, as that, assumingly ment to be a generic routine, is
anything but. Its fixed to a certain bit ammount, meaning that if you
change it to, for example, display a 32-bit value you loose the ability to
display an 8- or 16-bit one.

In other words: Spend a bit more time designing your low-level routines, so
that you can use them broad as possible without having to change anything.
*Especially* if they are ment to be of the cut-and-paste (generic) variety.

By the way: Why a "sub ecx,1", "jne .1" instead of a "loop .1" ?

> If I don't put them in available registers, they have to go
> in memory

Nope. You've loaded them before the loop, meaning you cannot reuse those
registers anywhere in it. Whats the problem just loading a register with
the divisor just before the DIV ?

But even if they would need to go into memory, what would be the problem
with that ? Speed ? With a loop doing screen output ? Really ?

But that speed-mongering would explain why your code is the structureless,
unmaintainable mess it now is.

As an example to your interviewer that you understood the problem as
presented it will absolutily fail though.

> - there is no such thing as "IDIV 3".

Shucks, you got me ! Somehow I always seem to think that IMUL has a
sister just like MUL does. My bad. (see how easy hit is to graciously
acknowledge that a mistake has been made ?)

> That's a perfectly valid point. I can afford to be lazy.
> SudoBIOS (while providing full access to the native
> motherboard BIOS) guarantees that only those registers and
> flags that return values are modified.

Yeah, I already got the feeling that that could be the case.

It also means that your code is *absolutily worthless* to anyone not having
that extender of yours (which by the way I, looking at what you posted here
and your Fireworks dis/re-assembly, would not want to touch with a 10-foot
pole).

> For the faint of heart the code is easily converted to
> 16 bit real mode (a place that I luckily (as you previously
> surmised) no longer have to go to.

True. Someone wanting to do that just has wrap all the bios calls in a
layer of pushes and pops to save and restore the possibly, by those bios
calls, clobbered registers. A childs play ofcourse.

Oh wait: That cannot be done indiscriminatly, some bios calls return data
in those registers.

So, that "easily" means you would have to work thru all the calls
seperatily, check what they return and push/pop apropriatily.

Sorry, not my kind of "easily" I'm afraid. Painstakingly (and prone to
mistakes) would be a more appropriate word.

> Both, and fully tested (by me of course), obviously someone
> here is talking through their (non-programmer) hat.

Shucks, you got me again: I took the line "a simple "freestanding" PM32
classic mode version" to be indicating a rather standard environment, not
one you created yourself. I just should have known you ment something
quite different, shouldn't I ?

Regards,
Rudy Wieser


-- Origional message:
Mike Gonta <mike...@nospicedham.gmail.com> schreef in berichtnieuws
nege2l$1ij7$1...@gioia.aioe.org...

Bernhard Schornak

unread,
Apr 11, 2016, 7:21:23 PM4/11/16
to
Short example of what I meant:


.data
.align 5,,31
fiz:.ascii "fizz"
.long 0x00
buz:.ascii "buzz"
.long 0x00
both:.ascii "fizzbuzz"
.long 0x00, 0x00

.text
.align 5,,31
main:< save registers >
xorl %ecx, %ebx
movl $0x03, %ecx
movl $0x05, %edx
.align 5,,31
loop:incl %ebx # EBX = number++
je XIT
cmpl %ecx, %edx # multiple of 3 and 5?
je is35
cmpl %ebx, %ecx # multiple of 3?
je is3
ret3:cmpl %ebx, %edx # multiple of 5?
je is5
jmp cvt

.align 5,,31
is3:addl $0x03, %ecx # ECX = next multiple of 3
movl $fiz, %edi # EDI = EA text
call print
jmp ret3

.align 5,,31
is5:addl $0x05, %edx # EDX = next multiple of 5
movl $buz, %edi # EDI = EA text
call print
jmp loop

.align 5,,31
is35:addl $0x03, %ecx # ECX = next multiple of 3
addl $0x05, %edx # EDX = next multiple of 5
movl $fibu, %edi # EDI = EA text
call print
jmp loop

.align 5,,31
print:...
ret

.align 5,,31
cvt:...
call print
jmp loop

.align 5,,31
XIT:< restore registers >
< insert exit code >


Comparison against trailing 5 or 0 is impossible with hexadecimal
processors: 0,05, 0x0A, 0x0F, 0x14 => 0101, 1010, 1111, 0100 - no
way to find an appropriate filter for ANDing. Thus, my "idea" was
a stupid assumption...

Mike Gonta

unread,
Apr 11, 2016, 8:06:32 PM4/11/16
to
"R.Wieser" wrote:

> I took the line "a simple "freestanding" PM32 classic mode
> version" to be indicating a rather standard environment,

Unfortunately there is no such thing as a standard
enviroment that permits the use of the BIOS while in 32 bit
protected mode. All modern boot loaders (many of which use
some form of BIOS extender to load files and print to the
screen) provide a "freestanding" PM32 environment. In this
case freestanding means independent of an operating system.
The type of program loaded is typically an operating system,
but simple games, utilities and snippets also qualify.
By "classic mode" I mean the same simple style of the bygone
16 bit real mode days. The difference here is that instead
of being hampered by the restrictive old time RM16, the
Classic Mode environment is PM32.

> not one you created yourself.

I didn't create the environment, I only set the BIOS free.
DPMI, v86 mode and the multitude of professional and
homegrown BIOS extenders have preceded me. In order to set
the BIOS free, the extender has to be completely
transparent, no setup, no extra calls etc. A manual is not
required only an understanding of the BIOS API. Once loaded
by the boot loader (mine - which is PM32 C - and also a
Classic Mode program, yours or someone elses), the program
is freestanding. Of course, it requires the BIOS, but that's
what makes Classic Mode simple and fun.

Benjamin David Lunt

unread,
Apr 11, 2016, 9:06:45 PM4/11/16
to

"Frank Kotler" <fbko...@nospicedham.myfairpoint.net> wrote in message
news:neh29b$k8e$1...@dont-email.me...
> Mike Gonta wrote:
>
> ...
>> Seems like "fishing" adds an extra dot where it should't be.
>
> Yeah, sorry 'bout that. I used to know why that happened - whose job it
> was to add that extra dot and whose job it was to remove it. I forget now.
> Used to happen quite a bit.


NNTP Specification
Section 2.4.1, second paragraph.

"If the text contained a period as the first character of the text
line in the original, that first period is doubled."

https://www.w3.org/Protocols/rfc977/rfc977



I remember this from back when I would post NBASM code, or
MASM code for that matter. Some of the directives start with
a period.

.model tiny
.code
.386

For NBASM, at the time, that period had to be in the first
column.

Ben

--
-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-
Forever Young Software
http://www.fysnet.net/index.htm
http://www.fysnet.net/osdesign_book_series.htm
To reply by email, please remove the zzzzzz's

Batteries not included, some Assembly required.


Rod Pemberton

unread,
Apr 12, 2016, 3:22:22 AM4/12/16
to
On Mon, 11 Apr 2016 20:50:23 +0200
Bernhard Schornak <scho...@nospicedham.web.de> wrote:

> You can omit the time consuming divisions if you compare EBP against
> 3 and EDI against 5. Jump to a label when equal and add 3 to EBP (or
> 5 to EDI), print the message and continue to compare against the new
> multiple of 3 or 5. Actually, all multiples of 5 either end with a 0
> or a 5, so you do not even need to add a separate counter, but check
> if ECX is zero or five. This saves an entire register you might need
> for the output routine.

If he initializes one register to 3 and the other to 5, he can just
decrement each and compare with zero. When zero, reset to either
3 or 5 appropriately. This avoids any need for modulo or division,
or larger register sizes.


Rod Pemberton

Rod Pemberton

unread,
Apr 12, 2016, 3:22:24 AM4/12/16
to
On Mon, 11 Apr 2016 08:00:16 -0400
Frank Kotler <fbko...@nospicedham.myfairpoint.net> wrote:

> FizzBuzz: db "FizzBuzz", 0
> Fizz: db "Fizz", 0
> Buzz: db "Buzz", 0
> hex: db "0x", 0
> comma: db ", ", 0
>
> look and see - many look but few see

Yup, you have "Fizz" and "Buzz". So, why
do you need "FizzBuzz" too? ...


Rod Pemberton

wolfgang kern

unread,
Apr 12, 2016, 4:22:32 AM4/12/16
to
isn't 'loop' a reserved term ?

> Comparison against trailing 5 or 0 is impossible with hexadecimal
> processors: 0,05, 0x0A, 0x0F, 0x14 => 0101, 1010, 1111, 0100 - no
> way to find an appropriate filter for ANDing. Thus, my "idea" was
> a stupid assumption...

Good that you figured this yourself ;)
binary dividible by 5: "if the nibble-sum is a multiple of 5" :)

but because the print routine may need conversion to ASCII before
display anyway, you could get your wanted "0,5,else" from there.

me too would avoid DIV and also 1/x MUL:

start:
mov ecx,1
mov edx,3
mov ebx,5
fb:
cmp ecx,edx
setz al
cmp ecx,ebx
setz ah
add al,al
or al,ah ;al=0,1,2,3 (non,bussy,fozzy,both)
jnz nonum

mov al,cl ;convert to ASCII-quad
...
; ie: eax become "100" 0x00303031 or " 99" 0x00393920
jmp L2

nonum:
cmp al,3
jz L0: ;FozzyBussy
cmp al,2
jnz L1 ;bussy only
mov eax,[txt+4]
jmp L2 ;fozzy only
L0:
mov eax,[txt+4]
call txt4
L1:
mov eax,[txt]
L2:
call txt4
mov eax,0x00000A0D
call txt4
inc ecx
add edx,3
add ebx,5
cmp ecx,0x65
jc fb
ret

txt4:
call char_out ;or use the BIOS here
shr eax,8
jnz txt4
ret

txt: db 'BussFozz'

servas,
__
wolfgang

Mike Gonta

unread,
Apr 12, 2016, 4:22:34 AM4/12/16
to
"Rod Pemberton" wrote:
> Frank Kotler wrote (not really):
>
>> FizzBuzz: db "FizzBuzz", 0
>> Fizz: db "Fizz", 0
>> Buzz: db "Buzz", 0
>> hex: db "0x", 0
>> comma: db ", ", 0
>>
>> look and see - many look but few see
>
> Yup, you have "Fizz" and "Buzz". So, why
> do you need "FizzBuzz" too? ...

Do you mean "looks" something like this to you?

<code>
; print "FizzBuzz"
mov esi, Fizz
call print_string ; print "Fizz"
call print_string ; print "Buzz"; this ain't no stinkin' C,
; I know exactly where "Buzz" is located and I know exactly
; how the "print_string" works internally and I refuse to
; to simplify my coding life by using anybodies other well
; defined API "blackbox" routines
<code>

I "see" something that "looks" like not so good "best
practice" coding.

On the other hand I am a big fan of the following:
<code>
; print oops1
mov esi, oops1
call print_string
mov esi, press_any_key
call print_string
....
; print oops2 ; make this one the popular "oops"
mov esi, oops2
call print_string
....
oops1: db "oops1", 0
oops2: db "oops2"
press_any_key: db "Press any key to continue ...", 0
</code>


Mike Gonta
look and see - many look but few see | ees wef tub kool ynam

PS. When looking into a mirror make sure there is no mirror
behind you.

http://mikegonta.com
http://tawk.to/mikegonta


Mike Gonta

unread,
Apr 12, 2016, 4:37:38 AM4/12/16
to
"Benjamin David Lunt" wrote:
> "Frank Kotler" wrote:
>> Mike Gonta wrote:
>> ...
>>> Seems like "fishing" adds an extra dot where it should't
>>> be.
>>
>> Yeah, sorry 'bout that. I used to know why that happened
>> - whose job it was to add that extra dot and whose job it
>> was to remove it. I forget now.
>> Used to happen quite a bit.
>
> NNTP Specification
> Section 2.4.1, second paragraph.
>
> "If the text contained a period as the first character of
> the text line in the original, that first period is
> doubled."
>
> https://www.w3.org/Protocols/rfc977/rfc977

Almost as "bad" as the GAS (Gnu Assembler) gotcha. GAS can't
handle the divide operator (/) properly since it is used a
comment indicator. Easily "fixed" with the GCC/AS "--divide"
option.

R.Wieser

unread,
Apr 12, 2016, 5:55:20 AM4/12/16
to
Mike,

> Unfortunately there is no such thing as a standard
> enviroment that permits the use of the BIOS while in
> 32 bit protected mode.

There however is a definition of how those BIOS calls are supposed to work,
as well as some more general speccing regarding to which register may,and
may not be clobbered by them.

> I didn't create the environment, I only set the BIOS free.

Do you think your FizzBuzz program would be able without that extension of
yours ? If not than it becomes, for anyone looking at that program and
wanting to run it, part of the environment.

> A manual is not required only an understanding of the BIOS API.

Not quite. Although from what I see you only seem to extend the used
registers, you *also* make sure only the result-registers are altered.
Thats a behavior definitily different from the BIOS API as I am aware of
(which even contains warnings that, in some case, important registers can
change for no good reason).

My knowledge of the BIOS API (which functions can clobber any of the
so-called "non important" registers and sometimes even more than those) led
me to believe you where either lucky, or hadn't tested the code.

So, although I would not need a full new manual, this "lets preserve
*everything*" behaviour is definitly note-worthy. Especially as you are
presenting us with code activily using that behaviour.

I do have a bit of a problem though, because of what you posted earlier (in
the "Control cursor keys" thread)
-------
mov edx, 0 ; start at 0,0
; light grey mouse on blue screen
mov ah, 9 ; write character and attribute to cursor position
mov ecx, 80*25
mov al, ' '
mov bl, 17h ; light grey on blue
int 10h
-------
Either that first line loading EDX with the initioal cursor location is
bogus, or you have altered how the INT 10h, AH=09h BIOS call function
actually works (according to Ralf Browns interrupt list)...


One more thing, just outof curiosity: I do not really see you using
procedures (setting up (E)BP to point to the local stack-frame, and use it
to refer to arguments and local variables). Not here, and not in that
fireworks re-assembly either. Does your assembler not support it, or do
you just not like full-fledged procedures (using stack-frames) ?

Regards,
Rudy Wieser

P.s.
As a throw-in a bit more generic form of your print_hex routine. As you
might notice, easy adaptable for any number of nibbles, and as easy
extensible (as shown). :-)

;----------------------------

Print_HexByte:
pusha
shl eax,32-4*2
mov cx,2
jmp Print_Hex0

;---------------

Print_HexLong:
pusha
; shl eax,32-4*8 ;A shift of Zero is superfluous ofcourse
mov cx,8

Print_Hex0:

;print, if wanted, a prefix here.

Print_Hex1:
rol eax,4
push eax
and al,0Fh
add al,'0'
cmp al,'9'
jbe Print_Hex2

add al,'A'-'9'+1
Print_Hex2:
mov bx,0007h ;Page #0 and, if in graphics mode, the characters color.
mov ah,0Eh
int 10h
pop eax
loop Print_Hex1

popa
ret

;----------------------------

Remarks:

#1: This will work for your "save and restore everything" BIOS calls.
For a more stndard environment CX needs to be pushed before the INT 10h call
and popped afterwards.
#2: loading BX can ofcourse be moved to just above the @@Print_Hex1 label.
Personally I like to keep the arguments as close to the (INT) call as I can.
#3: If you do not like to push-and-pop eax in the loop you're ofcourse free
to use a register instead.

One last remark: Personally I would convert the whole thing into a
procedure, and supply the value (and likely also the nibble-count) as
argument(s). But than again, my assembler of choice does quite well in
regard to suporting procedures (even upto accepting arguments on the same
line as the call to them), which is not a given for others.


-- Origional message:
Mike Gonta <mike...@nospicedham.gmail.com> schreef in berichtnieuws
nehdfc$18gq$1...@gioia.aioe.org...

R.Wieser

unread,
Apr 12, 2016, 6:40:27 AM4/12/16
to
Mike,

I think that my own preference to implementing a solution goes like this:

;----------------------------

FizzBuzz:
mov cx,1

FizzBuzz1:
lea si,[TXT_FizzBuzz]
mov al,[Mod3]
or al,[Mod5]
jz FizzBuzz2

lea si,[TXT_Fizz]
cmp [Mod3],0
je FizzBuzz2

lea si,[TXT_Buzz]
cmp [Mod5],0
je FizzBuzz2

;Output value CL here

lea si,[TXT_EOL]
FizzBuzz2:
;Output string SI here

inc [Mod3]
cmp [Mod3],3
jb FizzBuzz3

mov [Mod3],0
FizzBuzz3:
inc [Mod5]
cmp [Mod5],5
jb FizzBuzz4

mov [Mod5],0
FizzBuzz4:
inc cx
cmp cx,100
jb FizzBuzz1

int 20h

;---------------

Mod3 db 1
Mod5 db 1

TXT_Fizz db 'Fizz',13,10,0
TXT_FizzBuzz db 'Fizz'
TXT_Buzz db 'Buzz'
TXT_EOL db 13,10,0

;----------------------------

It does look a bit different than yours though. :-D

And yes, I left out the "print value" and "print string" routines. Deal
with it.

To be honest, a remark next to code Bernhard Schornak posted triggered me
to think about the usage of the above "modulo count". Thanks for that
Bernard. :-)

Regards,
Rudy Wieser

P.s.
I could also let those Mod3 and Mod5 counters go *backwards*, and than check
for the Sign bit to reload them. Would mean I could remove the compare
(currently below the increment of the counters, than decrement), but the
result would not be as easily understood I'm afraid. So, I left it as-is.



Terje Mathisen

unread,
Apr 12, 2016, 7:40:38 AM4/12/16
to
R.Wieser wrote:
> Mike,
>
> I think that my own preference to implementing a solution goes like this:
>
> ;----------------------------
>
> FizzBuzz:
> mov cx,1
>
> FizzBuzz1:
> lea si,[TXT_FizzBuzz]
> mov al,[Mod3]
> or al,[Mod5]
> jz FizzBuzz2

As you note at the bottom, you could also decrement and avoid the CMP
operations when checking for modulo wraparound...

I don't see any need to use memory variables here, let's keep the ode
faster and smaller!

org 100h

mov di,0503h ; Mod counters
mov bx,'00' ; Digits to print

increment_counter:
inc bh ; Increment second/least significant byte
cmp bh,'9'
jbe increment_done
sub bx,0a00h - 1 ; Reset second byte to '0', increment first byte

increment_done:
mov [number],bx

sub di,0101h ; Decrement both mod3 and mod5 counters
mov cx,0503h ; Reset both counters
mov dx, offset FizzBuzz
jz print

test di,0ffh ; Mod 3 counter in bottom byte
lea cx,[di+3] ; Bottom byte updated!
mov dx, offset Fizz
jz print

test di,0ff00h ; Mod 5 in top half
lea cx,[di+0500h] ; Top byte updated
mov dx, offset Buzz
jz print

; Default to printing the actual number
mov cx,di
mov dx, offset number
cmp bl,'0'
jne no_leading_zero
inc dx

print:
mov di,cx ; New, updated DI counter pair

mov ah,9
int 21h ; Print '$' terminated string

cmp bx,'99'
jbe increment_counter

ret

number dw ?
db 13,10,'$'
FizzBuzz db 'Fizz'
Buzz db 'Buzz',13,10,'$'
Fizz db 'Fizz',13,10,'$'

R.Wieser

unread,
Apr 12, 2016, 8:25:46 AM4/12/16
to
Terje,

> I don't see any need to use memory variables here, let's
> keep the ode faster and smaller!

:-) I guess my lack in recent 16-bit DOS programming was talking there. A
while after I posted I realized that the counter could go into BX (which
does not get clobbered by the used INT 21h call(s)), and that the INT 21h,
Ah=09h, DOS string output could be used, freeing up SI to be used with DI as
modulo counters (do not get clobbered either).

Your usage of DI for *both* modulo counters is even better though.

Also a good find is your usage of a text-mode decimal counter. It does
away with any kind of value-to-text translation stuff (though I think I
would have ditched BX and just used the chars "number" points at though).

In short, I would,as a possible candidate for the job, choose you over that
other, me. :-D

Regards,
Rudy Wieser


-- Origional message:
Terje Mathisen <terje.m...@nospicedham.tmsw.no> schreef in berichtnieuws
neim54$144g$1...@gioia.aioe.org...

Mike Gonta

unread,
Apr 12, 2016, 9:10:56 AM4/12/16
to
"R.Wieser" wrote:
> Mike,
>
>> Unfortunately there is no such thing as a standard
>> enviroment that permits the use of the BIOS while in
>> 32 bit protected mode.
>
> There however is a definition of how those BIOS calls are
> supposed to work, as well as some more general speccing
> regarding to which register may,and may not be clobbered
> by them.

And you're complaining that I changed all of that and didn't
tell anyone.

>> I didn't create the environment, I only set the BIOS free.
>
> Do you think your FizzBuzz program would be able without
> that extension of yours ?

If you are referring to my comment that it could be easily
converted to RM16, I didn't mean to imply cut & paste. For
example, I use a small custom script to convert existing
RM16 code (ie. MikeOS) to Classic Mode after which I still
go over it by hand to clean it up and make small changes. I
probably didn't notice the "required" saving and restoring
which I would have still left in (even though SudoBIOS makes
such things redundant) since the code conversion process is
actually a translation - it is in this sense that the code
is "exactly" the same.

> If not than it becomes, for anyone looking at that program
> and wanting to run it, part of the environment.

And they need a PC and a keyboard and a monitor and
permission from their parents (just kidding).
So what's the big deal, Linux code needs Linux, Windows code
needs Windows, etc. etc.

>> A manual is not required only an understanding of the
>> BIOS API.
>
> Not quite. Although from what I see you only seem to
> extend the used registers, you *also* make sure only the
> result-registers are altered. Thats a behavior definitily
> different from the BIOS API as I am aware of which even
> contains warnings that, in some case, important registers
> can change for no good reason).
>
> My knowledge of the BIOS API (which functions can clobber
> any of the so-called "non important" registers and
> sometimes even more than those) led me to believe you
> where either lucky, or hadn't tested the code.
>
> So, although I would not need a full new manual, this
> "lets preserve *everything*" behaviour is definitly
> note-worthy. Especially as you are presenting us with
> code activily using that behaviour.

All you had to say was "Where can I get a copy of this
this fantastic new invention and how much does it cost?"

> I do have a bit of a problem though, because of what you
> posted earlier (in the "Control cursor keys" thread)

It's always best not to mix up two different threads
(especially when the refence to the other thread is
something like "Fireworks dis/re-assembly") however and
since you brought it up.

> -------
> mov edx, 0 ; start at 0,0
> ; light grey mouse on blue screen
> mov ah, 9 ; write character and attribute to cursor position
> mov ecx, 80*25
> mov al, ' '
> mov bl, 17h ; light grey on blue
> int 10h
> -------
> Either that first line loading EDX with the initioal
> cursor location is bogus, or you have altered how the
> INT 10h, AH=09h BIOS call function actually works
> (according to Ralf Browns interrupt list)...

Actually, that's a bug (and would have made a good
non-argumentative discussion back then). Originally my
following line was a call to "move_mouse" which, of course
is move_cursor but I wanted to keep the naming consistent
with the OP's original "mouse" theme. I removed it, (without
thinking) because I thought (well I actually do some
thinking) that it might be a little confusing if I move the
"mouse" before I define the "mouse". I was testing it in
MikeOS32 (I have a "better" environment called Flash Live
which is my current project and almost but not yet quite
ready for release), which I was suggesting could be used for
testing, verification (and more importantly - FUN). I was
using the MikeOS32 TUI (as I described) to load the file,
which clears the screen and effectively locates the cursor
at 0,0 so I didn't notice it. Had I loaded it from the
MikeOS32 command line I would have noticed it then - so I
didn't actually "fully" test it. Clearing the screen and
locating the cursor to 0,0 will definitely be an added
feature of boot loader.

> One more thing, just outof curiosity: I do not really see
> you using procedures (setting up (E)BP to point to the
> local stack-frame, and use it to refer to arguments and
> local variables). Not here, and not in that fireworks
> re-assembly either. Does your assembler not support it,
> or do you just not like full-fledged procedures (using
> stack-frames) ?

Just a personal preference. I use GAS/FASM/NASM/GCC not
necessarily in that order (and of course not all at the same
time). The "proc" business is either MASM/TASM directives or
GAS/FASM/NASM/YASM/ETCM macros (I don't recall any GAS
macros - but then that's what GCC is for) so it's probably
best to present small code snippets in generic "intel"
format.

[sniped a very good code example to cut to the chase]

> One last remark: Personally I would convert the whole
> thing into a procedure, and supply the value (and likely
> also the nibble-count) as argument(s). But than again,
> my assembler of choice does quite well in regard to
> suporting procedures (even upto accepting arguments on the
> same line as the call to them), which is not a given for
> others.

Nevertheless, things have advanced quite far since the
"ancient" days of TASM/MASM. The macro facilities of FASM
and NASM (YASM uses NASM internally) can do exactly the same,
FASM even has a "masm" mode. Some would say that C is much
better at supporting procedures and that an optimizing C
compiler is their assembler of choice.

Bernhard Schornak

unread,
Apr 12, 2016, 9:26:04 AM4/12/16
to
wolfgang kern wrote:


> Bernhard Schornak wrote:
>

<snip code>

> isn't 'loop' a reserved term ?


As instruction: Yes. As jump label: No. The only reserved label
is "main" (it is reserved as entry point for the OS launcher).


>> Comparison against trailing 5 or 0 is impossible with hexadecimal
>> processors: 0,05, 0x0A, 0x0F, 0x14 => 0101, 1010, 1111, 0100 - no
>> way to find an appropriate filter for ANDing. Thus, my "idea" was
>> a stupid assumption...
>
> Good that you figured this yourself ;)
> binary dividible by 5: "if the nibble-sum is a multiple of 5" :)
> but because the print routine may need conversion to ASCII before display anyway, you could get your
> wanted "0,5,else" from there.


Which costs a lot of headaches and time. The brute force method
beats that by far.


> me too would avoid DIV and also 1/x MUL:
>
> start:
> mov ecx,1
> mov edx,3
> mov ebx,5
> fb:
> cmp ecx,edx
> setz al cmp ecx,ebx
> setz ah
> add al,al
> or al,ah ;al=0,1,2,3 (non,bussy,fozzy,both)
> jnz nonum
>
> mov al,cl ;convert to ASCII-quad
> ...
> ; ie: eax become "100" 0x00303031 or " 99" 0x00393920 jmp L2


This code requires a lot of those "partial register merges" AMD
warns us not to use:

AMD "Software Optimization Guide for AMD Family 15h Processors"
PDF 47414, page 86, point 5.5 "Partial-Register Writes"


> nonum:
> cmp al,3
> jz L0: ;FozzyBussy


Wasn't that "FozzyWozzy"? ;)

Bernhard Schornak

unread,
Apr 12, 2016, 9:41:14 AM4/12/16
to
Yes, but:

1. I took the register size from Mike's code.

2. On modern processors, partial register reads and writes might
slow down the code due to the required "register merging". It
is a good idea to use the "native" register size - 32 bit for
x86(-64) machines - to guarantee fastest possible handling.

3. Replacing the two comparisons with decrements saves two byte.
The remaining four lines (assignining the next multiples of 3
and/or 5) keep their size, only the ADD is replaced by a MOV.


Where we really could save time (but not code) is the conversion
routine:

/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
d2str dword => unformatted hex string HHHHHHHHzzzzzzzz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-> RCX qword to convert (only the low dword is converted!)
RDX EA target
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<- RAX 0000 0000
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
BUFFER 0 1 2
0123456789ABCDEF0123456789ABCDEF0123456789ABCDEF

01234567zzzzzzzz
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
average latency ~ 8 clock cycles
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
.p2align 5,,31
.globl _d2str
.def _d2str; .scl 2; .type 32; .endef
_d2str:subq $0xF8, %rsp
movq _BNR(%rip), %rax # RAX = BNR
bswap %ecx # RCX = [3210]
movdqa %xmm4, 0xD0(%rsp)
movdqa %xmm5, 0xE0(%rsp)
movd %ecx, %xmm0 # X00 = full nibbles
movdqa CVT_09(%rax), %xmm3 # X03 = 090909...09
movdqa %xmm0, %xmm1 # X01 = full nibbles
movdqa CVT_0F(%rax), %xmm4 # X04 = 0F0F0F...0F
psrlq $0x04, %xmm1 # X01 = high nibbles
movdqa CVT_07(%rax), %xmm5 # X05 = 070707...07
punpcklbw %xmm0, %xmm1 # interleave LHLHLHLH
movdqa CVT_30(%rax), %xmm2 # X02 = 303030...30
leaq CVTCUT(%rax), %rax # RAX = EA CVTCUT
pand %xmm4, %xmm1 # reduce to nibbles
movdqa %xmm1, %xmm0 # copy for correction
pcmpgtb %xmm3, %xmm1 # mask A...Fs => FFs
paddb %xmm2, %xmm0 # convert
pand %xmm5, %xmm1 # reduce FFs to 07
movdqa 0xD0(%rsp), %xmm4
paddb %xmm1, %xmm0 # A...F correction
movdqa 0xE0(%rsp), %xmm5
pand 0x80(%rax), %xmm0 # clear upper half
bswap %ecx # RCX = [0123]
xorl %eax, %eax # RAX = 0
movdqu %xmm0, 0x00(%rdx) # store DQ (upper half is 0000...00)
addq $0xF8, %rsp
ret


This really fast conversion requires 5 lookup tables with a size
of 16 byte, each, adding another 80 byte to the total size. How-
ever, you need this very fast conversion routine anywhere, so it
probably is part of your conversion library, anyway. (At least -
that's where I took it from.)

You only need an appropriate output routine "print" to show your
results light grey on black or in a window or edit control:


/*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WnSDT SetDlgItemText() 23
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-> RCX DQ HWND
RDX DQ resource ID
R08 VOID* address buffer
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<- RAX RC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
.p2align 5,,31
dlgtxs:call *__imp__SetDlgItemTextA(%rip)
jmp XIT


Which also is a part of a library - "XIT" restores all registers
clobbered by the OS call. As you may have noticed, that's 64 bit
code. To transfer it to 32 bit, you had to remove all references
to RIP - RIP relative addressing is reserved for long mode...

My libraries are here:

https://drive.google.com/open?id=0B1OgMlxNnSNEVnJNeTNSeEM1bTQ

Excerpts from [ST8\LIB\SOURCES\CORE\], cap.S and cvt.S

Mike Gonta

unread,
Apr 12, 2016, 10:57:01 AM4/12/16
to
"Bernhard Schornak" wrote:
> wolfgang kern wrote:
>> Bernhard Schornak wrote:
> <snip code>
>> isn't 'loop' a reserved term ?
> As instruction: Yes. As jump label: No.

It is in FASM but not in NASM.
".loop" works fine in both except that dot labels
are only accessable within a pair of regular labels,
which should be sufficient for loops except in this
case where you are "JMP"ing into the loop from outside.

Rick C. Hodgin

unread,
Apr 12, 2016, 12:27:29 PM4/12/16
to
On Monday, April 11, 2016 at 8:46:37 AM UTC-4, Mike Gonta wrote:
> "Frank Kotler" wrote:
> > Ooops! Got fumble-fingered and almost accidentally
> > rejected this one, but fished it out of the bin. This is
> > from Mike Gonta, not me. Sorry Mike!
>
> No problem Frank.
> I also believe in giving credit where credit is due.
> http://forum.osdev.org/viewtopic.php?f=2&t=30280

Anyone can write a FizzBuzz algorithm. It's much more complex to write
a Fizzbin algorithm (especially if it's dark... on Tuesday):

http://memory-alpha.wikia.com/wiki/Fizzbin

Show me an efficient assembly algorithm to play Fizzbin, and then I'll
be duly impressed. :-)

Best regards,
Rick C. Hodgin

R.Wieser

unread,
Apr 12, 2016, 12:42:49 PM4/12/16
to
Mike,

> And you're complaining that I changed all of that
> and didn't tell anyone.

Complaining ? Yes, if you want to blow it up that far.

You *did* change the "rules" of the game without telling anyone *and*
activily used those changed rules, now did you ?

> > Do you think your FizzBuzz program would be able without
> > that extension of yours ?
>
> If you are referring to my comment that it could be
> easily converted to RM16

I cannot even begin to try to understand how you made that jump. Sorry.

And no, those (used environment and convertability) are two distinctly
different points.

> If you are referring to my comment that it could be easily
> converted to RM16, I didn't mean to imply cut & paste.

And neither did I, as you *could* have deduced from my response to it. I
haven't got the foggiest why you didn't.

> > If not than it becomes, for anyone looking at that program
> > and wanting to run it, part of the environment.
>
> And they need a PC and a keyboard and a monitor and
> permission from their parents (just kidding).

... which most (adult) people (if not al) using a desktop have. By default.
Your point ?

> All you had to say was "Where can I get a copy of this
> this fantastic new invention and how much does it cost?"

When ? Before or after I mentioned that you where either lucky or did not
test that code ? And why ? *You're* the one deviating from what most
others use. Don't you than think its upto you to mention that ?

You sound like a salesman from hell: "You did not ask if there actually was
a motherboard in this desk/laptop enclosure, so its your own fault". "You
did not ask us if the version of Windows we gave you is actually legal, so
its your own fault". and so on.

And as I already said, I currently want nothing to do with that "fantastic
new invention" of yours, as I've got trouble with believing that your code
does not barf all over the place. (now looking at that Fireworks program)
Using ESP directly in code is maybe a good idea for a compiler, but
definitily *not* for hand-written assembly. And using EBP with numeric
offsets ? That is as if you are calculating the offsets of relative jumps
by yourself. Too prone to (small) mistakes resulting in interresting, but
mostly ending in GPFs, code execution.

> It's always best not to mix up two different threads

Did I mix them up ? How ? I simply referred to something I saw you do
there.

Besides, you dropped that thread (much like a hot potato ...)

> Actually, that's a bug (and would have made a good
> non-argumentative discussion back then).

And I would, as I do now, have accepted that as an explanation and left it
at that.

As for that "argumentative discussion" style ? Thats what happens when I
get "this is how it is" kind of statements thrown at me, but nothing to
support such a stance. I also have quite a problem with
multi-interpretable lingo, and than being cut off/ignored when I ask for
clarification.

Alas, I've never been able to adopt a "whatever, this isn't worth my time"
attitude and simply drop any such non-conversations.

You know, its odd: Somehow even simple absolutily factoid technical
questions of mine seem to cause a "you do not believe me, you thus are the
enemy" kind of response. Its something I never understood, and probably
never will.

> Just a personal preference.

Thanks for the reply. It does make it harder for others to track what your
code is doing or though, as wel as making it *quite* a bit harder to make
any changes to it.

> The "proc" business is either MASM/TASM directives or
[snip]

I'm using Borlands Tasm, version 5.x . Somewhere in the neigbourhood of 20
years old. (yeah, I know: *ancient* by most peoples standards :-) ).

> The macro facilities of FASM and NASM (YASM uses
> NASM internally) can do exactly the same, FASM even
> has a "masm" mode.

A friend of mine recently had a go at Assembly on his Linux computer. I
can't remember which assember he used, but I do know he had to jump thru
hoops to get anything *near* to automatic stack-frame building and tear-down
as wel as accessing arguments and local variables to work. Also, no kind of
argument count or type/size checking seemed to be available. Do you have a
different experience with it ?

> Some would say that C is much better at supporting procedures

And I would reply that that fully depends on the support the assembler has
for it. :-)

Mine seems to have a rather decent support for it, so its absolutily easy to
use them.
For example, a procedure can be typed as a C or C++ style one with the
addition of a single specifier. The neccesary changes to the code (reverse
argument pushing, throwing arguments away after the call to it returns) are
handled by the assembler.

> and that an optimizing C compiler is their assembler of choice.

I've disasembled enough C{something}compiler masticated code to know first
hand that some of it is ... remarkable to say the least.

Besides, looking at what some C{something} programmers have as source code
its painfully clear they have absolutily no idea what is going on under the
hood (resulting in often quite wastefull solutions for even the simpelest of
problems).

Regards,
Rudy Wieser


-- Origional message:
Mike Gonta <mike...@nospicedham.gmail.com> schreef in berichtnieuws
neirbr$1ecu$1...@gioia.aioe.org...

wolfgang kern

unread,
Apr 12, 2016, 2:13:18 PM4/12/16
to

Mike Gonta replied and I think he wont hire me:

perhaps just he can't afford :)

> "Bernhard Schornak" wrote:
>> wolfgang kern wrote:
>> <snip code>

>>> isn't 'loop' a reserved term ?
>> As instruction: Yes. As jump label: No.

> It is in FASM but not in NASM.
> ".loop" works fine in both except that dot labels
> are only accessable within a pair of regular labels,
> which should be sufficient for loops except in this
> case where you are "JMP"ing into the loop from outside.

in return I wont ever hire anyone who think too different to my aspect,
so I never used such an stupidity-check on atept membership requests.
__
wolfgang

wolfgang kern

unread,
Apr 12, 2016, 3:13:34 PM4/12/16
to

Rick C. Hodgin asked about:

> Anyone can write a FizzBuzz algorithm. It's much more complex to write
> a Fizzbin algorithm (especially if it's dark... on Tuesday):

> http://memory-alpha.wikia.com/wiki/Fizzbin

> Show me an efficient assembly algorithm to play Fizzbin, and then I'll
> be duly impressed. :-)

Ok I'm ready to do, but just tell me how much would you pay for it ?

only a few side-tasks are to add to any normal game like this, it
will take some time (but not many bytes) to write such an algo.
__
wolfgang

Bernhard Schornak

unread,
Apr 12, 2016, 5:14:16 PM4/12/16
to
Mike Gonta wrote:


> "Bernhard Schornak" wrote:
>> wolfgang kern wrote:
>>> Bernhard Schornak wrote:
>> <snip code>
>>> isn't 'loop' a reserved term ?
>> As instruction: Yes. As jump label: No.
>
> It is in FASM but not in NASM.
> ".loop" works fine in both except that dot labels
> are only accessable within a pair of regular labels,
> which should be sufficient for loops except in this
> case where you are "JMP"ing into the loop from outside.


Okay. I posted code for AS, the GNU assembler, where "loop"
is a valid name for a label (as was "ret" which is equal to
the RET mnemonic).

Benjamin David Lunt

unread,
Apr 12, 2016, 6:29:46 PM4/12/16
to

"Frank Kotler" <fbko...@nospicedham.myfairpoint.net> wrote in message
news:neg376$k9u$1...@dont-email.me...
> Ooops! Got fumble-fingered and almost accidentally rejected this one, but
> fished it out of the bin. This is from Mike Gonta, not me. Sorry Mike!
>
> Best,
> Frank
>
>
> Here is a simple "freestanding" PM32 classic mode version of
> FizzBuzz. https://en.wikipedia.org/wiki/Fizz_buzz
> "Fizz buzz has been used as an interview screening device
> for computer programmers. Creating a list of the first 100
> Fizz buzz numbers is a trivial problem for any would-be
> computer programmer, so interviewers can easily sort out
> those with insufficient programming ability."
> Note: "real programmers" use hexadecimal notation and
> assembly language.

Okay guys, this sounds like a size optimizing competition.

I took Rudy's code and modified it slightly to give the
base code (see below. Also, watch for those double periods)

This code generates 147 bytes. After a half hour or so,
I got it down to 90 bytes. What do you think?

Just post your code here, or shall I write up simple rules?
If I make out some rules, don't post your code, just post
your results. "I got 90 bytes", kind of thing.

Just curious.
Ben


; assembled with NBASM
; http://www.fysnet.net/newbasic.htm

.model tiny
.code
.186

org 100h

FizzBuzz:
mov cx,1

FizzBuzz1:
mov dx,offset TXT_FizzBuzz
mov al,Mod3
or al,Mod5
jz short FizzBuzz2

mov dx,offset TXT_Fizz
cmp byte Mod3,0
je short FizzBuzz2

mov dx,offset TXT_Buzz
cmp byte Mod5,0
je short FizzBuzz2

;Output value CX here
call print_dec

mov dx,offset TXT_EOL
FizzBuzz2:
;Output string here
mov ah,9
int 21h

inc byte Mod3
cmp byte Mod3,3
jb short FizzBuzz3

mov byte Mod3,0
FizzBuzz3:
inc byte Mod5
cmp byte Mod5,5
jb short FizzBuzz4

mov byte Mod5,0
FizzBuzz4:
inc cx
cmp cx,100
jb short FizzBuzz1

.exit


print_dec proc near uses ax cx dx
mov ax,cx
push 0FFFFh
mov cx,10
PD1: xor dx,dx
div cx ; Divide by 10
add dl,'0' ; Convert to ASCII
push dx ; Store remainder
or ax,ax ; Are we done?
jnz short PD1 ; No, so continue
PD2: pop dx ; Character is now in DL
cmp dx,0FFFFh ; Is it the ending flag?
je short PD3 ; Yes, so continue
mov ah,02h
int 21h
jmp short PD2 ; Keep doing it
PD3: ret
print_dec endp

;---------------

Mod3 db 1
Mod5 db 1

TXT_Fizz db 'Fizz',13,10,'$'
TXT_FizzBuzz db 'Fizz'
TXT_Buzz db 'Buzz'
TXT_EOL db 13,10,'$'

.end


Benjamin David Lunt

unread,
Apr 12, 2016, 6:59:54 PM4/12/16
to
Re: Competition request

P.S. I didn't check it for accuracy. It may or may not
put out the correct items. I was just interested in
size optimization. :-)

Ben


Rod Pemberton

unread,
Apr 12, 2016, 6:59:56 PM4/12/16
to
On Tue, 12 Apr 2016 04:18:31 -0400
"Mike Gonta" <mike...@nospicedham.gmail.com> wrote:

> "Rod Pemberton" wrote:
> > Frank Kotler wrote (not really):

> >> FizzBuzz: db "FizzBuzz", 0
> >> Fizz: db "Fizz", 0
> >> Buzz: db "Buzz", 0
> >> hex: db "0x", 0
> >> comma: db ", ", 0
> >>
> >> look and see - many look but few see
> >
> > Yup, you have "Fizz" and "Buzz". So, why
> > do you need "FizzBuzz" too? ...
>
> Do you mean "looks" something like this to you?
>
> <code>
> ; print "FizzBuzz"
> mov esi, Fizz
> call print_string ; print "Fizz"
> call print_string ; print "Buzz"; this ain't no stinkin' C,
> [snide comment snipped]
> <code>

While that would work too, I was thinking
restructured for more fall-through.

E.g., (untested):

push ebx
and ebx, edx
pop ebx

je .0
call print_hex
jmp again
..0:

test edx, edx
jne .1
mov esi, Fizz
call print_string
..1:

test ebx, ebx
jne .2
mov esi, Buzz
call print_string
..2:

jmp again


Rod Pemberton

wolfgang kern

unread,
Apr 13, 2016, 3:50:11 AM4/13/16
to
Your code show an old styled (80186) 16-bit DOS.com file
which may only run on DOS-emulators today.
I'd like to use modern CPU-instructions and OS-independent
code, either 16 or 32 bit, much more.

when I remember the rules of this old kids-game, it wasn't
allowed to say any matching number. So I'd add the rule to
printout ie:

1
2
fizz
4
buzz

__
wolfgang

R.Wieser

unread,
Apr 13, 2016, 6:21:16 AM4/13/16
to
Benjamin,

> Okay guys, this sounds like a size optimizing competition.

> This code generates 147 bytes. After a half hour or so,
> I got it down to 90 bytes. What do you think?

There was no way I could get that low using my earlier posted method.

But using a bit different approach (marking if either Buzz or Fizz was
printed, and than skipping the number printing, a method mentioned in this
thread) I got down to 86 bytes. COM style, ending with a RET*.

*Suggestion: Lets only count the actual bytes used for the FizzBuzz problem,
not any preamble and termination code. Those are OS and executable style
mandated, for which the latter not everyone has a free choice. Ofcourse,
in that case my solution is just 85 bytes. :-)

I think I did cheat a bit though: I used an AAM 10 instruction (officially
undocumented as far as I know) in the conversion of the counter to a
human-readable result ...

Regards,
Rudy Wieser



Terje Mathisen

unread,
Apr 13, 2016, 8:06:57 AM4/13/16
to
That's on "oldie but goldie", a well-known trick for small but slow
code. :-)

I hand-counted (without actually assembling it) the version I posted a
few days ago, it looked like 100-105 bytes, of which more than 20 are
the constant strings.

It is interesting that you get smaller code with a binary loop counter
and explicit (although tricky) conversion to ascii. :-)

The last time i worked seriously to minimize code size was when I wrote
Dos TSRs to replace the built-in drivers from Microsoft/IBM:

The originals used 20-60 kB while my replacement (with better
functionality/features) needed 704 bytes (rounded up to the next 16-byte
paragraph).

This piece of code was needed in order to make it possible to run big
streadsheets (or other large programs) here in Norway: With the
originals developed in the US they used all available memory so there
was no room left for the OS keyboard/screen font drivers.

HP here in Norway used to steal this program and give it to customers
with the same memory size problems, when we caught them red-handed they
refused to pay for a license but promised to never do it again.

Less than a year later we caught them again (!), the difference this
time was that the salescritters who distributed my program told the
customers to keep it secret. :-(

Adding insult to injury, when they still wouldn't pay, my bosses again
refused to allow me to take them to court, so we didn't get a single
cent (kroner).

Terje

R.Wieser

unread,
Apr 13, 2016, 9:22:43 AM4/13/16
to
Terje,

> That's on "oldie but goldie", a well-known trick for small
> but slow code. :-)

Whoops ... Shows my age a bit ?

And I made a mistake: AAM is actually well documented: dividing AL by 10.
Its the "AAM" with a divisor other than 10 thats not documented (my command
reference list remarks to use a "db 0D4h, {constant}" construction). On
the other hand, my assembler does not seem to have a problem with it ...

> The last time i worked seriously to minimize code size was when I wrote
> Dos TSRs to replace the built-in drivers from Microsoft/IBM:
>
> The originals used 20-60 kB while my replacement (with better
> functionality/features) needed 704 bytes (rounded up to the next 16-byte
> paragraph).

Ouch! You might wonder what the origional programmer was thinking of when
he wrote his (bloated) version ...

Although I've never been a "any trick goes, as long as the result is
smaller" -guy (readability/maintainability is more important to me) I've
always tried to keep my code as tight as possible.

> Adding insult to injury, when they still wouldn't pay, my bosses
> again refused to allow me to take them to court, so we didn't
> get a single cent (kroner).

A direct a result of cold-hard calculation no doubt: If HP would have
decided that, because of you going to court for what is rightfully
yours/your companies, they activily disliked your company that could cost
*way* more than what it would bring.

And although I understand that simple fact I also have problems with letting
them get away with it (just imagine what would happen if the tables where
turned). Laws fail to work in cases like these. :-\

Regards,
Rudy Wieser


-- Origional message:
Terje Mathisen <terje.m...@nospicedham.tmsw.no> schreef in berichtnieuws
nelc5j$1beg$1...@gioia.aioe.org...

Mike Gonta

unread,
Apr 13, 2016, 9:53:20 AM4/13/16
to
"Frank Kotler" wrote:
> Ooops! Got fumble-fingered and almost accidentally rejected this one,

Maybe this one too.

My fizzbuzzters are here:
https://groups.google.com/forum/#!topic/alt.os.development/wOkef2tZ9OQ
and here, and here and here
http://board.flatassembler.net/topic.php?t=19087
http://forum.osdev.org/viewtopic.php?f=2&t=30280
https://www.reddit.com/r/osdev/new/

I'm OK with a little "abuse" in "moderation", however
when people start taking out their 10 foot poles ....



Terje Mathisen

unread,
Apr 13, 2016, 10:23:38 AM4/13/16
to
R.Wieser wrote:
> Terje,
>
>> That's on "oldie but goldie", a well-known trick for small
>> but slow code. :-)
>
> Whoops ... Shows my age a bit ?
>
> And I made a mistake: AAM is actually well documented: dividing AL by 10.
> Its the "AAM" with a divisor other than 10 thats not documented (my command
> reference list remarks to use a "db 0D4h, {constant}" construction). On
> the other hand, my assembler does not seem to have a problem with it ...
>
>> The last time i worked seriously to minimize code size was when I wrote
>> Dos TSRs to replace the built-in drivers from Microsoft/IBM:
>>
>> The originals used 20-60 kB while my replacement (with better
>> functionality/features) needed 704 bytes (rounded up to the next 16-byte
>> paragraph).
>
> Ouch! You might wonder what the origional programmer was thinking of when
> he wrote his (bloated) version ...

They used big general-purpose tables that had entries for every possible
combination of key down/key up and shift keys, this made it possible to
use exactly the same code for all countries.

They also replicated all the BIOS logic instead of chaining back to it
for all codes/combinations that didn't need modification.
>
> Although I've never been a "any trick goes, as long as the result is
> smaller" -guy (readability/maintainability is more important to me) I've
> always tried to keep my code as tight as possible.
>
>> Adding insult to injury, when they still wouldn't pay, my bosses
>> again refused to allow me to take them to court, so we didn't
>> get a single cent (kroner).
>
> A direct a result of cold-hard calculation no doubt: If HP would have
> decided that, because of you going to court for what is rightfully
> yours/your companies, they activily disliked your company that could cost
> *way* more than what it would bring.

That was probably the logic, except it was unfortunately more a case of
"that nice HP salesman use to take us out for nice dinners every year,
and he'll get in trouble if we report him".

At the time Hydro (the company I worked for) was by far the largest
corporation in Norway, with ~100 K employees spread over 77 countries,
i.e. we were similar to HP worldwide, and orders of magnitude larger in
Norway.
>
> And although I understand that simple fact I also have problems with letting
> them get away with it (just imagine what would happen if the tables where
> turned). Laws fail to work in cases like these. :-\

That was exactly why I wonted to make them pay at least enough to make
it hurt a bit, so they wouldn't try it for a third round.

Frank Kotler

unread,
Apr 13, 2016, 10:38:47 AM4/13/16
to
I'm not sure what you're getting at here, Mike. If anything but that one
message got "abused", I'm not aware of it, and if so I apologize.

Best,
Frank

R.Wieser

unread,
Apr 13, 2016, 11:24:48 AM4/13/16
to
Mike,

> I'm OK with a little "abuse" in "moderation", however
> when people start taking out their 10 foot poles ....

That is obviously directed at me.

If you had the choice, would you rather have it that I flat-out lied to you
? If it would make you feel better I could try I suppose. Its just that
I'm not all that good at it I'm afraid. Never have been.

Also, its nothing personal. Even if you would have been my best friend I
would not allow any code like that near to a machine of mine (other than
some delete-after-done, experimental 20-line-ish code perhaps).

I tried to put forward, in rather technical terms, what your code looks to
me (unmaintainable and effectivily un-alterable), and even tried to explain
why I thought so. Do you think I was false, untruthfull or maybe even
malicious in that ?

Regards,
Rudy Wieser


-- Origional message:
Mike Gonta <mike...@nospicedham.gmail.com> schreef in berichtnieuws
neliit$1mmk$1...@gioia.aioe.org...

McHoogilan

unread,
Apr 13, 2016, 2:25:36 PM4/13/16
to
On Mon, 11 Apr 2016 08:00:16 -0400, Frank Kotler
<fbko...@nospicedham.myfairpoint.net> wrote:

>Here is a simple "freestanding" PM32 classic mode version of
>FizzBuzz.

For Windoze -- small and simple, no divides, proper output formatting. Who
can improve it?

global Start ;04/13/16
section .text

Start: MOV DX,503H ;Initialize Mod 3 & mod 5 down counts
XOR ESI,ESI ;Initialize number
MOV EDI,OutBuf ;Point to output buffer
PUSH EDI ;Save output buffer pointer
@@10: XOR EBX,EBX ;"No text printed"
INC ESI ;Adjust number
DEC DL ;Mod 3 = 0?
JNZ short @@20 ;No
MOV EAX,'Fizz' ;\__ 'Fizz'
STOSD ;/
INC EBX ;"Text printed"
MOV DL,3 ;Reload mod 3 down count
@@20: DEC DH ;Mod 5 = 0?
JNZ short @@30 ;No
MOV EAX,'Buzz' ;\__ 'Buzz'
STOSD ;/
INC EBX ;"Text printed"
MOV DH,5 ;Reload Mod 5 down count
@@30: TEST BL,BL ;Text printed?
JNZ short @@50 ;Yes
MOV EAX,ESI ;Number to AL
AAM ;Binary to unpacked BCD
TEST AH,AH ;1st digit is 0?
JZ short @@40 ;Yes
XOR AH,'0' ;BCD digit to ASCII
MOV [EDI],AH
INC EDI ;Write 1st digit
@@40: XOR AL,'0' ;BCD digit to ASCII
STOSB ;Write 2nd digit
@@50: MOV AL,0DH ;|
STOSB ;|
MOV AL,0AH ;|-- Write CR/LF
STOSB ;|
CMP ESI,100 ;Done?
JB short @@10 ;No
POP ESI ;Restore output buffer pointer

PUSH -11 ;Windoze!!!
CALL GetStdHandle ;Get standard console output handle
SUB EDI,ESI ;Calculate output data length
PUSH EAX ;Create temp chars-written return var
MOV ECX,ESP ;Temp variable pointer to ECX
PUSH 0 ;Reserved
PUSH ECX ;Chars-written return variable pointer
PUSH EDI ;Character count
PUSH ESI ;String pointer
PUSH EAX ;Console output handle
CALL WriteConsoleA ;Write string to console
POP EAX ;Throw away temporary variable
PUSH 0 ;Exit code
CALL ExitProcess

section .bss
OutBuf resb 1024 ;Output buffer

extern ExitProcess,GetStdHandle,WriteConsoleA

..bat to build:
@echo off
nasm -f win32 FizzBuzzNasm.asm -o FizzBuzzNasm.obj
GoLink.exe /console /entry Start FizzBuzzNasm.obj kernel32.dll
del FizzBuzzNasm.obj

Robert Wessel

unread,
Apr 13, 2016, 9:46:03 PM4/13/16
to
On Wed, 13 Apr 2016 15:16:01 +0200, "R.Wieser"
<add...@nospicedham.not.available> wrote:

>Terje,
>
>> That's on "oldie but goldie", a well-known trick for small
>> but slow code. :-)
>
>Whoops ... Shows my age a bit ?
>
>And I made a mistake: AAM is actually well documented: dividing AL by 10.
>Its the "AAM" with a divisor other than 10 thats not documented (my command
>reference list remarks to use a "db 0D4h, {constant}" construction). On
>the other hand, my assembler does not seem to have a problem with it ...


Intel has documented AAM (and AAD) with operands other than 10 for
years. They also point out that for most assemblers you have to code
the instruction directly for values other than 10.

Terje Mathisen

unread,
Apr 14, 2016, 1:47:44 AM4/14/16
to
McHoogilan wrote:
> On Mon, 11 Apr 2016 08:00:16 -0400, Frank Kotler
> <fbko...@nospicedham.myfairpoint.net> wrote:
>
>> Here is a simple "freestanding" PM32 classic mode version of
>> FizzBuzz.
>
> For Windoze -- small and simple, no divides, proper output formatting. Who
> can improve it?

Nice approach, generating the entire output and printing it in a single
call. :-)

>
> global Start ;04/13/16
> section .text
>
> Start: MOV DX,503H ;Initialize Mod 3 & mod 5 down counts
> XOR ESI,ESI ;Initialize number
> MOV EDI,OutBuf ;Point to output buffer
> PUSH EDI ;Save output buffer pointer
> @@10: XOR EBX,EBX ;"No text printed"
> INC ESI ;Adjust number
> DEC DL ;Mod 3 = 0?
> JNZ short @@20 ;No
> MOV EAX,'Fizz' ;\__ 'Fizz'
> STOSD ;/
> INC EBX ;"Text printed"
> MOV DL,3 ;Reload mod 3 down count
> @@20: DEC DH ;Mod 5 = 0?
> JNZ short @@30 ;No
> MOV EAX,'Buzz' ;\__ 'Buzz'
> STOSD ;/
> INC EBX ;"Text printed"
> MOV DH,5 ;Reload Mod 5 down count
> @@30: TEST BL,BL ;Text printed?

This could have been TEST EBX,EBX as well, I don't think it matters for
the size?

> JNZ short @@50 ;Yes
> MOV EAX,ESI ;Number to AL
> AAM ;Binary to unpacked BCD
> TEST AH,AH ;1st digit is 0?
> JZ short @@40 ;Yes
> XOR AH,'0' ;BCD digit to ASCII
> MOV [EDI],AH
> INC EDI ;Write 1st digit
> @@40: XOR AL,'0' ;BCD digit to ASCII
> STOSB ;Write 2nd digit

Above here you could have combined some of the ops:

AAM
ADD AX,'00'
CMP AH,'0'
JE skip
MOV [EDI],AH
INC EDI
skip:
STOSB


> @@50: MOV AL,0DH ;|
> STOSB ;|
> MOV AL,0AH ;|-- Write CR/LF
> STOSB ;|

This would be better as a single store:
MOV AX,0dh + 0a00h
STOSW

R.Wieser

unread,
Apr 14, 2016, 3:33:38 AM4/14/16
to
Robert,

> Intel has documented AAM (and AAD) with operands other
>than 10 for years.

Sorry, not in my 2003 "Intel Instruction Set Reference" document I'm afraid.
It specifies that the AAM has an implicit divisor thats fixed to 10.

It does however mention "The generalized version of this instruction allows
adjustment of the contents of the AX to create two unpacked digits of any
number base", and defines it as "D4 ib - (No mnemonic) - Adjust AX after
multiply to number base imm8".

Maybe I should have been more carefull with my "not documented" though, and
should have said that it "doesn't show a mnemonic for it".

> They also point out that for most assemblers you have to code
> the instruction directly for values other than 10.

You mean their "To adjust to values in another number base, the instruction
must be hand coded in machine code (D4 imm8)." remark ? Yes. Thats why I
was surprised by the fact and mentioned that my 17 year old assembler (a bit
older than the document) had no problem with accepting an "AAM imm8"
construction.

Regards,
Rudy Wieser


Robert Wessel <robert...@nospicedham.yahoo.com> schreef in berichtnieuws
mbttgbdd28k3mii89...@4ax.com...

wolfgang kern

unread,
Apr 14, 2016, 4:49:16 AM4/14/16
to

Benjamin David Lunt challenged:

> Okay guys, this sounds like a size optimizing competition.

:) fine,

> I took Rudy's code and modified it slightly to give the
> base code (see below. Also, watch for those double periods)

> This code generates 147 bytes. After a half hour or so,
> I got it down to 90 bytes. What do you think?

> Just post your code here, or shall I write up simple rules?
> If I make out some rules, don't post your code, just post
> your results. "I got 90 bytes", kind of thing.

interesting that my first try on this show the same size:
67 byte for code and 23 for data.
It's not shorter when I use INT10 instead of INT21.

__
wolfgang

assumed a DOS.com file:

0100 mov bx,0503h
0103 mov cl,01
0105 mov dh,01
L0:
0107 mov ax,0503h
010a mov ch,cl
010c cmp cx,bx
010e jnz L1
0110 mov dl,44h ;both
0112 add bx,ax
0114 jmp L4
L1:
0116 cmp cl,bh
0118 jnz L2
011a mov dl,48h ;buzz
011c add bh,ah
011e jmp L4
L2:
0120 cmp cl,bl
0122 jnz L3
0124 mov dl,4fh ;fizz
0126 add bl,al
0128 jmp L4
L3:
012a mov al,cl
012c aam
012e or ax,3030h
0131 exch al,ah
0133 mov [0156h],ax
0136 mov dl,56h ;num
L4:
0138 mov ah,09
013a int 0x21
013c inc cx
013d cmp cl,65h
0140 jc L0
0142 ret

txt:
0144 db "fizzbuzz" 0x0a 0xd 0x24
014f db "fizz" 0x0a 0x0d $
0156 db 0x20 0x20 0x0a 0x0d 0x24
015b ...free

Benjamin David Lunt

unread,
Apr 14, 2016, 4:42:15 PM4/14/16
to

"Benjamin David Lunt" <zf...@nospicedham.fysnet.net> wrote in message
news:nejsma$1b9n$1...@gioia.aioe.org...
>
> Okay guys, this sounds like a size optimizing competition.
>

Sorry for the late reply.

So that we can be host independent, how about something
like this:

;--------------------------------------------------------
; start of .asm file
;---------
;
; any start up code that is needed for that host.
;
;
;---------

actual_start:
;---------
; calculation code
; including two 'call's (used as many times as needed)
;
; call outside_print_decimal
; call outside_print_string
;
;
;---------
; necessary static data
;
actual_end:

;---------
;
mov eax,actual_end - actual_start
call outside_print_decimal

; host dependant termination code
; ...

outside_print_decimal:
; ...
;

outside_print_string:
; ...
;
;--------

; end of .asm file
;--------------------------------------------------------


The calculation code cannot use any outside code or data,
nor rely on any outside code or data, including it cannot
rely on any register setting returned from either 'outside'
call except that all registers are preserved.

This would probably work, ya?

Ben


McHoogilan

unread,
Apr 14, 2016, 6:27:35 PM4/14/16
to
On Thu, 14 Apr 2016 07:36:33 +0200, Terje Mathisen
<terje.m...@nospicedham.tmsw.no> wrote:

>This could have been TEST EBX,EBX as well, I don't think it matters for
>the size?

Yes, they are the same size.

000007EF 84 DB TEST BL,BL
000007F1 85 DB TEST EBX,EBX

I reserved BH in case the interviewer added a new requirement to the task.

>Above here you could have combined some of the ops:
>
> AAM
> ADD AX,'00'
> CMP AH,'0'
> JE skip
> MOV [EDI],AH
> INC EDI
>skip:
> STOSB

Both are the same number of bytes.

000007F9 84 E4 TEST AH,AH
000007FB 74 06 JZ short @@40
000007FD 80 F4 30 XOR AH,'0'
00000800 88 27 MOV [EDI],AH
00000802 47 INC EDI
00000803 34 30 @@40: XOR AL,'0'
00000805 AA STOSB

00000806 66| 05 3030 ADD AX,'00'
0000080A 80 FC 30 CMP AH,'0'
0000080D 74 03 JZ short @@45
0000080F 88 27 MOV [EDI],AH
00000811 47 INC EDI
00000812 AA @@45: STOSB

In this case, I believe better understanding of the source when viewed many
years later outweighs any possible speed advantage inherent in the second
form. My first version of this code had AL and AH being converted in a
single operation (but XOR instead of ADD). I changed it when I realized it
saved no bytes.

Another consideration is that different assemblers treat multiple characters
inside quotes differently. Here, '00' would never matter, but something like
'12' could have endian issues when ported say from TASM to NASM.

>This would be better as a single store:
> MOV AX,0dh + 0a00h
> STOSW

Once again, it's the same number of bytes (although possibly slower).

00000813 B0 0D @@50: MOV AL,0DH
00000815 AA STOSB
00000816 B0 0A MOV AL,0AH
00000818 AA STOSB

00000819 66| B8 0A0D MOV AX,0A0DH
0000081D 66| AB STOSW

And, once again, I chose the form that would more easily be understood many
years down the road.

It is important to note that many tricks from the 8 and 16-bit days (MsDOS) no
longer work when coding for 32-bit Windoze and Linux.

So, do I get the job or what?

Robert Wessel

unread,
Apr 15, 2016, 12:58:47 AM4/15/16
to
I have a PIII era (1999) Intel reference where they document the
instruction. OTOH, it's been known that AAM just does a division by
the value in the second byte since the first days of the 8086, some
four decades now, Intel has just documented it more recently. SALC is
another undocumented instruction from 8086 onward, although Intel has
not yet deigned to document it. In either case there have been
assemblers for quite some time which accept those (both NASM and FASM,
for example, which also support a number of other undocumented
instructions).

In any event, whatever the mnemonics and syntax Intel has assigned,
that's clearly not something every assembler has followed - just look
at (non-Intel mode) GAS.

Kerr Mudd-John

unread,
Apr 15, 2016, 6:35:06 AM4/15/16
to
Another appraoch to FizzBuzz I found following the Forth guys discussion,
this uses a bit vector approach; as they note it fails if you need to mod
the code later to add "boom" and "zap".

Analysis here:
https://groups.google.com/forum/#!search/forth$20fizzbuzz$20magic$20numbers/comp.lang.forth/tLZLCc02gmk/cwFAQsILIQgJ

--
Bah, and indeed, Humbug

Kerr Mudd-John

unread,
Apr 27, 2016, 12:20:15 PM4/27/16
to
org 0x100 ; FizzBuzz MJ countdown 5s and 3s - 82 bytes
xor cx,cx ; total count goes up
mov bx,0x0305 ; bh= threes, bl=fives ; bin 00330555
eachnum:
inc cx ; tot
dec bh ; 3s
jnz not3
mov bh,3 ; reset
mov dx,Fizz ; dl unsets "unprinted" flag
call dos_prtstrg
not3:
dec bl
jnz not5
mov bl,5
mov dx,Buzz
call dos_prtstrg
not5:
cmp dl,0x4A ; hard coded crlf offset from prev prt;
"unprinted" flag
jne dunprint
; else print num from cl ; 17 bytes
mov al,cl
aam ; /10d
;; suppress leading zero?
or ax,0x3030
mov dl,ah ; high digit
mov ah,2
push ax
; cmp dl,0x30 ; costs 5
; je no_leading_zero
int 0x21
no_leading_zero:
pop dx ; low digit dl from prev al
int 0x21

dunprint:
mov dx,crlf ; also sets "unprinted" flag
call dos_prtstrg
cmp cx,100
jl eachnum
; exit
ret
dos_prtstrg:
mov ah,9
int 0x21
ret
; text
Fizz db "Fizz$"
Buzz db "Buzz$"
crlf db 0x0D,0x0A,"$"

Kerr Mudd-John

unread,
May 11, 2016, 8:36:50 AM5/11/16
to
New, Improved! 71 bytes (77 with leading zero suppression)
Pure 8086, easily amended for 7 Bang and 11 Zapp.

org 0x100 ; FizzBuzz MJ 1 rtn [ 71 ] [ +6 ] for nldz
cpu 8086
eachnum:
inc bx ; tot counts up
mov dx,Prtarea
mov di,dx
mov si,Fizznum-4 ; allow fallthru
notz:
lodsw ; skip FBstr
lodsw
nextFB:
dec byte [si] ; count down
jl dunallFB ; terminating 0 goes -ve, and keeps -ve
lodsw ; al=num, ah=reset ; si->txt
jnz notz ; then skip txt to next
mov byte [si-2],ah ; reset count
mov cl,4 ; text must be 4 chars long.
repnz movsb ; add FBstr
jmp nextFB
dunallFB:
cmp dx,di ; if no text added prtnum
jne goprt
mov ax,bx ; prtnum
aam ; /10d
or ax,0x3030
xchg ah,al
stosw ; with leading Z [ 3 ]
;; suppress leading zero
; cmp ah,0x30 ; [ 9 ]
; jz nlz
; mov [di],ah
; inc di
;nlz: stosb
goprt:
mov ax,0x0A0D ; addcrlf$ [ 6 ]
stosw
mov byte [di],'$' ;eos
mov ah,9
int 0x21
cmp bl,100
jl eachnum
exit: ret
Fizznum:
db 3,3,"Fizz"
db 5,5,"Buzz"
cntdn db 0 ; endFB - total count < 128
Prtarea equ $

R.Wieser

unread,
May 11, 2016, 10:01:31 AM5/11/16
to
Kerr,

> easily amended for 7 Bang and 11 Zapp.

If for nothing else you score some points for that. :-)

> New, Improved! 71 bytes (77 with leading zero suppression)

You've shown that first putting everything in a buffer and than print the
whole line does save bytes. However, you've not included the size of the
needed buffer. If you would have my previous (non-posted) version printing
all three strings seperatily would have still have been smaller (78 against
71+11).

But ... Using your "first combine, print everything together" method I was
able to get my version down to 64 bytes (not including the buffer, and no
leading-zero suppression).

I however did use a bit of a trick though ... Hint: The string "FizzBuzz"
is present at DS:0082. :-)

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhas2...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 11, 2016, 3:02:18 PM5/11/16
to
On Wed, 11 May 2016 16:09:43 +0100, Kerr Mudd-John <ad...@127.0.0.1> wrote:
resend
> On Wed, 11 May 2016 15:00:30 +0100, R.Wieser
> <add...@nospicedham.not.available> wrote:
>
>> Kerr,
>>
>>> easily amended for 7 Bang and 11 Zapp.
>>
>> If for nothing else you score some points for that. :-)
> some praise!
>>
>>> New, Improved! 71 bytes (77 with leading zero suppression)
>>
>> You've shown that first putting everything in a buffer and than print
>> the
>> whole line does save bytes. However, you've not included the size of
>> the
>> needed buffer. If you would have my previous (non-posted) version
>> printing
>> all three strings seperatily would have still have been smaller (78
>> against
>> 71+11).
> I had 82 (but it didn't print the first "1"!!)
>>
>> But ... Using your "first combine, print everything together" method I
>> was
>> able to get my version down to 64 bytes (not including the buffer, and
>> no
>> leading-zero suppression).
>>
>> I however did use a bit of a trick though ... Hint: The string
>> "FizzBuzz"
>> is present at DS:0082. :-)
> you mean you passed the text as a parameter string? shame!
> almost as weasily as assuming bx=0 on entry!
>
>>
>> Regards,
>> Rudy Wieser
>
> Well go on then print your code!

R.Wieser

unread,
May 11, 2016, 5:02:36 PM5/11/16
to
Kerr,

>> I however did use a bit of a trick though ... Hint: The string
>> "FizzBuzz"
>> is present at DS:0082. :-)
>
> you mean you passed the text as a parameter string? shame!

Not me, the OS. DS:0080 points is where the commandline is stored in a COM
style program. The first thing you find there (after the byte counter) is
the name of the program itself. As I have named the program "FizzBuzz.com"
and I start it as such that "fizzbuzz.com" string is the first stored in
that buffer followed by whatever you type as "arguments".

It ofcourse goes quite wrong if the program is started with anything like a
drive letter and/or path in front of the program name (I did not name it a
trick for nothing ...)

Though even without using that trick and getting the "fizz" and "buzz"
strings from within my code (as well as using your below-mentioned default
COM-style register contents) I'm now down to 65 bytes.

> almost as weasily as assuming bx=0 on entry!

Oeh! The size of my tricked program just went down to 62 bytes ! :-D

I should have noticed that I guess, but was only looking at why you only
loaded CL (ignoring CH) for the "rep movsb" loop. :-\

> Well go on then print your code!

Why ? I mean, I'm leeching all you guys good ideas, combine them with
pretty-much the only origional one I had myself, and thereby keep ahead.
Isn't that how the game is played ? :-p :-D



Here it is though:

- - - - - - - - - - - - - - - -
org 0100h

FizzBuzz:
xor bx,bx ;Yes, yes. This one isn't needed. :-)
FizzBuzz1:
inc bx ;Increment current number

mov si,0082h ;Point at 'FizzBuzz' program name
mov dx,offset sBuffer ;Output string buffer
mov di,dx ;Output string current pointer

mov cl,04h ;# of bytes to copy

mov ax,bx
aam 03h ;Divisable by 3 ? (aam w/divisor 3 (ah quotient, al remainder) )
jnz FizzBuzz2 ;Nope

rep movsb ;Copy first 4 chars of filename

FizzBuzz2:
add si,cx ;Update filename pointer

mov cl,04h ;# of bytes to copy

mov ax,bx
aam 05h ;Divisable by 5 ? (aam w/divisor 3 (ah quotient, al remainder) )
jnz FizzBuzz3 ;Nope

rep movsb ;Copy second 4 chars of filename

FizzBuzz3:
cmp di,dx ;Anything written to output buffer ?
jnz FizzBuzz4 ;Yep: Do not write the current counter

;-- convert a 0..99 value in SI to two ASCII digits in AX
mov ax,bx
aam ;Divide AL by 10 (ah quotient, al remainder)
xchg al,ah
add ax,'00'
stosw

FizzBuzz4:
mov ax,0D0Ah ;Add a LF,CR combination
stosw ;/
mov byte ptr [di],'$' ;And add an EOL

mov ah,09h ;Single print of full output string
int 21h ;/

cmp bx,20 ;Done yet ?
jb FizzBuzz1 ;Nope

ret

sBuffer db 16 dup()

- - - - - - - - - - - - - - - -

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhbaz...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 11, 2016, 5:32:40 PM5/11/16
to
On Wed, 11 May 2016 21:52:36 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

> Kerr,
>
>>> I however did use a bit of a trick though ... Hint: The string
>>> "FizzBuzz"
>>> is present at DS:0082. :-)
>>
>> you mean you passed the text as a parameter string? shame!
>
> Not me, the OS. DS:0080 points is where the commandline is stored in a
> COM
> style program. The first thing you find there (after the byte counter)
> is
> the name of the program itself. As I have named the program
> "FizzBuzz.com"

Not on olde DOS, IIRC. lots of my ancient asm progs look at the PSP there
for parameters.
https://en.wikipedia.org/wiki/Program_Segment_Prefix

It doesn't show up if run under GRDB.
[]

> Why ? I mean, I'm leeching all you guys good ideas, combine them with
> pretty-much the only origional one I had myself, and thereby keep ahead.
> Isn't that how the game is played ? :-p :-D
>

I think it's only us 2 "battling it out", and you're clearly ahead!

Nice use of aam.
Bah, and indeed, Humbug

Terje Mathisen

unread,
May 12, 2016, 1:48:20 AM5/12/16
to
I have an extremely obvious improvement to suggest:

You use the following code to copy either fizz or buzz into the target
buffer:

mov cl,04h ;# of bytes to copy

mov ax,bx
aam 05h ;Divisable by 5 ? (aam w/divisor 3 (ah quotient, al remainder) )
jnz FizzBuzz3 ;Nope

rep movsb ;Copy second 4 chars of filename

right?

You don't need the MOV CL,4 at all since you can replace the two-byte
REP MOBSB operation with a pair of MOVSW!

This saves 4 bytes immediately. :-)

Terje

R.Wieser

unread,
May 12, 2016, 4:03:34 AM5/12/16
to
Terje,

> You don't need the MOV CL,4 at all since you can replace the
> two-byte REP MOBSB operation with a pair of MOVSW!

Shucks, you're right.

It will only work for the second string-copy though, not the first. The
"Fizz" part either needs to be copied or skipped. The "rep" command causing
CX to become zero is part of the method there (next command is either adding
four or zero to DI).

It does chip of another two bytes though.

... that is, if the OS actually does reliable put the filename at DS:0082.

Regards,
Rudy Wieser


-- Origional message:
Terje Mathisen <terje.m...@nospicedham.tmsw.no> schreef in berichtnieuws
nh1515$ac7$1...@gioia.aioe.org...

R.Wieser

unread,
May 12, 2016, 4:03:36 AM5/12/16
to
Kerr,

> Nice use of aam.

Thanks. :-)

> > The first thing you find there (after the byte counter) is
> > the name of the program itself.

> Not on olde DOS, IIRC.

I always test my programs before claiming something like that, and indeed
found the filename there.

It turns out I still did blunder around a bit. Worse of all, it already
nagged my mind but I could not directly put a finger on it ... :-\

It turns out that the filename I found at DS:0082 is (most likely) a
(side-)result of me first running the program under "debug.exe", as well as
the PSP not being erased before being build when starting the program
directly, causing the once-created filename to stay available there. The
nagging was caused by me ignoring the byte at 0080 (00) and taking the EOL
(0D) at 0081 as the length of the commandline. Mea culpa.

I hereby ofcourse retract my previously posted solution.

I do have a previous version instead though. 65 bytes (not counting the
buffer, no leading zero suppression). Would have been 67 if I would not
have taken a que from you in regard to some registers already being
initialized to Zero though ... :-)

- - - - - - - - - - - - - - - - - - - -
org 0100h

FizzBuzz:
; xor si,si ;Is zet to Zero on entry of the COM-style program
FizzBuzz1:
inc si ;Increment current number

mov dx,offset sBuffer
mov di,dx

mov ax,si
aam 03h ;Divisable by 3 ? (aam w/divisor 3 (ah quotient, al remainder) )
jnz FizzBuzz2 ;Nope

mov ax,'iF'
stosw
mov ax,'zz'
stosw

FizzBuzz2:
mov ax,si
aam 05h ;Divisable by 5 ? (aam w/divisor 5 (ah quotient, al remainder) )
jnz FizzBuzz3 ;Nope

mov ax,'uB'
stosw
mov ax,'zz'
stosw
FizzBuzz3:
cmp di,dx
jnz FizzBuzz4

;-- convert a 0..99 value in SI to two ASCII digits in AX
mov ax,si
aam ;Divide AL by 10 (ah quotient, al remainder)
xchg al,ah
add ax,'00'
stosw

FizzBuzz4:
mov ax,0D0Ah
stosw
mov byte ptr [di],'$'

mov ah,09h
int 21h

cmp si,20
jb FizzBuzz1

ret

;---------------

Siz_FizzBuzz equ ($-FizzBuzz)

sBuffer db 16 dup(?)

- - - - - - - - - - - - - - - - - - - -

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhbht...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 14, 2016, 4:22:32 PM5/14/16
to
On Thu, 12 May 2016 08:58:55 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

[]
>
> I do have a previous version instead though. 65 bytes (not counting the
> buffer, no leading zero suppression). Would have been 67 if I would not
> have taken a que from you in regard to some registers already being
> initialized to Zero though ... :-)
>
> - - - - - - - - - - - - - - - - - - - -
> org 0100h
>
> FizzBuzz:
> ; xor si,si ;Is zet to Zero on entry of the COM-style program
not quite, it's 0100

...

> cmp si,20
so you'd need a cmp si,0120 here.
same code size though!
...


http://www.hugi.scene.org/compo/compoold.htm
e.g. hc16fin.zip
\_Rules\General.txt:

8-<-----------------------------------------------------------------------
Unless stated otherwise, your entry must NOT
... depend on its file name, i.e. it still has to work after renaming
it to, say, FOOBAR.EXE, or any other valid DOS executable file name.
... depend on its drive or path.
/8-<----------------------------------------------------------------------

8-<----------------------------------------------------------------------
You may assume that
... the registers have these values (all in hex):
(xx - means an unknown value which MUST NOT be assumed)

EAX = xxxx****
AL = 00 if first FCB has valid drive letter, FF if not
AH = 00 if second FCB has valid drive letter, FF if not
EBX = xxxx0000
ECX = xxxx00FF
EDX = xxxxxxxx
DX = CS = DS = ES = SS = xxxx, 0080 <= DX <=9000.
ESI = xxxx0100
EDI = xxxxFFFE
EBP = xxxx09xx
ESP = xxxxFFFE
EIP = xxxx0100

EFLAGS (binary) = xxxxxxxx xxxxxxxx xxxx0x1x xx0x0x1x
i.e.
DF = 0
IF = 1
other flags = x

WORD [FFFE] = 0000
Layout of PSP: see [Memory Layout]

/8-<----------------------------------------------------------------------

8-<----------------------------------------------------------------------
Format of Program Segment Prefix (PSP) (located at initial DS:0000):
[according to Ralf Brown's Interrupt List]

Offset Size Description (Table 01378)
00h 2 BYTEs INT 20 instruction for CP/M CALL 0 program termination
the CDh 20h here is often used as a signature for a valid
PSP
02h WORD segment of first byte beyond memory allocated to program
note: do not assume that this word contains 0A000h
04h BYTE (DOS) unused filler
05h BYTE CP/M CALL 5 service request (FAR CALL to absolute 000C0h)
06h WORD CP/M compatibility--size of first segment for .COM files
08h 2 BYTEs remainder of FAR JMP at 05h
0Ah DWORD stored INT 22 termination address
0Eh DWORD stored INT 23 control-Break handler address
12h DWORD DOS 1.1+ stored INT 24 critical error handler address
16h WORD segment of parent PSP
18h 20 BYTEs DOS 2+ Job File Table, one byte per file handle, FFh =
closed
2Ch WORD DOS 2+ segment of environment for process (see #01379)
2Eh DWORD DOS 2+ process's SS:SP on entry to last INT 21 call
32h WORD DOS 3+ number of entries in JFT (default 20)
34h DWORD DOS 3+ pointer to JFT (default PSP:0018h)
38h DWORD DOS 3+ pointer to previous PSP (default FFFFFFFFh in 3.x)
3Ch BYTE DOS 4+ (DBCS) interim console flag (see AX=6301h)
3Dh BYTE (APPEND) TrueName flag (see INT 2F/AX=B711h)
3Eh 2 BYTE ?
40h 2 BYTEs DOS 5+ version to return on INT 21/AH=30h
42h 7 BYTE ?
49h BYTE unused by DOS versions <= 6.00
4Ch WORD ?
4Eh 2 BYTEs unused by DOS versions <= 6.00
50h 3 BYTEs DOS 2+ service request (INT 21/RETF instructions)
53h 2 BYTEs unused in DOS versions <= 6.00
55h 7 BYTEs unused in DOS versions <= 6.00; can be used to make first
FCB
into an extended FCB
5Ch 16 BYTEs first default FCB, filled in from first commandline argument
overwrites second FCB if opened
6Ch 16 BYTEs second default FCB, filled in from second commandline
argument
overwrites beginning of commandline if opened
7Ch 4 BYTEs unused
80h 128 BYTEs commandline / default DTA
command tail is BYTE for length of tail, N BYTEs for the
tail,
followed by a BYTE containing 0Dh
/8-<----------------------------------------------------------------------



luckily the low (so <256) byte of SI *is* zero on entry, so you're OK.

but using the progname is out!


[]

R.Wieser

unread,
May 15, 2016, 4:38:40 AM5/15/16
to
Kerr,

> > ; xor si,si ;Is zet to Zero on entry of the COM-style
> program not quite, it's 0100

Not when I run MS own DEBUG.EXE (which I used as a reference). But I've
just printed the contents of those registers (before doing anything else),
and those values seem to match the Ralf Brown's numbers. Shows you you
can't trust *anyone*, not even MS :-)

> so you'd need a cmp si,0120 here.
> same code size though!

Shucks, forgot to change it to the required end value. But yes, In that
case either account for the high byte of SI being 01 *or* use the BX
register instead.

> http://www.hugi.scene.org/compo/compoold.htm

I'm sorry, but those rules where not present in the origional post.
Default register contents where not mentioned either.

> but using the progname is out!

Luckily I already retracted that version. :-)

Thanks for the heads-up. I seem to have forgotten more than I realized. :-(

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhgye...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 15, 2016, 9:08:56 AM5/15/16
to
On Sun, 15 May 2016 09:30:38 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

>
>> http://www.hugi.scene.org/compo/compoold.htm
>
> I'm sorry, but those rules where not present in the origional post.
> Default register contents where not mentioned either.
>
>> but using the progname is out!
>
> Luckily I already retracted that version. :-)
>
> Thanks for the heads-up. I seem to have forgotten more than I realized.
> :-(
[]

Heh. I've now *increased* my prog. It's more maintainable, yet hopefully
as small as possible.

trick to save 1 byte in printing, and 1 by hardcoding the Prtarea - I
think you could use that 2nd one.

org 0x100 ; FizzBuzz MJ A [ 70 ]
cpu 8086
; at start ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx
mov dx,Prtarea ; harded code dword
eachnum:
inc bx ; tot counts up
mov di,dx ; reset to print next
mov si,Texttbl-textlth ; allow fallthru
notz:
add si,textlth ; now variable!
; lodsw ; skip Textstr (hard code 4, saves [ 1 ])
; lodsw
nextFB:
dec byte [si] ; count down
jl dunallFB ; terminating 0 goes -ve, and keeps -ve
lodsw ; al=num, ah=reset ; si->text
jnz notz ; then skip txt to next
mov byte [si-2],ah ; reset count
mov cl,textlth
repnz movsb ; cpy Textstr
jmp nextFB
dunallFB:
cmp dx,di ; if not FB, cpynum
jne goprt
mov ax,bx ; [ cpynum 9 ]
aam ; ah=al/10d, al=al mod 10d
or ax,dx ; to ascii num - hard code dx to 3030
xchg ah,al ; other endian
stosw ; with leading Z
goprt:
inc si ; [addcrlf$ 10 ]
movsw ; add crlf
lodsw ; mov ah,9
stosb ; add eos
int 0x21 ; print it.
cmp bl,100 ; check for end [ 5 ]
jl eachnum
exit: ret

textlth equ 4
Texttbl: db 3,3,"Fizz"
db 5,5,"Buzz"
; db 7,7,"Bang"
; db 11,11,"Zapp"
cntdn db 0 ; endFB
crlf db 0x0D,0x0A,0x24,0x09

Prtarea equ 0x3030 ; hard code a dw saves 1

R.Wieser

unread,
May 15, 2016, 10:54:05 AM5/15/16
to
Kerr,

> trick to save 1 byte in printing, and 1 by hardcoding the
> Prtarea - I think you could use that 2nd one.

Thats a rather nasty trick you're using there, putting the buffer in la-la
land -- what happens when your code is loaded in a memory space just big
enough for your code ?

Hmmm ... I just realized that I also can't remember what happens with SP
if a program is loaded in a some memory space smaller than 64 KB. Could be
because the very first thing I always do is to load SP (most often to
0x0100) ...

And a suggestion for improvement (taken from my own code): do not add a
constant to SI, but take the CX register instead (saves exactly a single
byte :-) ):

- - - - - - - - - - - - - - - -

mov si,offset Texttbl
nextFB:
dec byte ptr [si] ; count down
jl dunallFB ; terminating 0 goes -ve, and keeps -ve

mov cl,textlth ;Use CX as a byte-copy or ptr-updating value

lodsw ; al=num, ah=reset ; si->text
jnz notz ; then skip txt to next

mov byte ptr [si-2],ah ; reset count
repnz movsb ; cpy Textstr - CX will be Zero after this command

notz:
add si,cx
jmp nextFB

- - - - - - - - - - - - - - - -

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhh9b...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 15, 2016, 4:29:42 PM5/15/16
to
On Sun, 15 May 2016 15:47:51 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

> Kerr,
>
>> trick to save 1 byte in printing, and 1 by hardcoding the
>> Prtarea - I think you could use that 2nd one.
>
> Thats a rather nasty trick you're using there, putting the buffer in
> la-la
> land -- what happens when your code is loaded in a memory space just big
> enough for your code ?

It is! (nasty!)
>
> Hmmm ... I just realized that I also can't remember what happens with
> SP
> if a program is loaded in a some memory space smaller than 64 KB. Could
> be
> because the very first thing I always do is to load SP (most often to
> 0x0100) ...
>
I think you're allowed to assume a (small) stack on boot; it should be at
FFFE in DOS

> And a suggestion for improvement (taken from my own code): do not add a
> constant to SI, but take the CX register instead (saves exactly a single
> byte :-) ):
>

[] Thanks, sorry I didn't spot what you were doing; nice trick!

R.Wieser

unread,
May 16, 2016, 3:32:11 AM5/16/16
to
Kerr,

> I think you're allowed to assume a (small) stack on boot; it
> should be at FFFE in DOS

Thats the problem, it assumes that your COM program has always *at least* 64
KByte of memory allocated on load. Which I'm not all that sure of ...

> [] Thanks, sorry I didn't spot what you were doing; nice trick!

No worries. I myself had trouble recognising your trick loading DX with
3030. Took a bit of time for the coin to drop. :-)

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhitr...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 16, 2016, 5:32:24 AM5/16/16
to
On Mon, 16 May 2016 08:19:22 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

> Kerr,
>
>> I think you're allowed to assume a (small) stack on boot; it
>> should be at FFFE in DOS
>
> Thats the problem, it assumes that your COM program has always *at
> least* 64
> KByte of memory allocated on load. Which I'm not all that sure of ...
>

The original IBM PCjr had 64k, though the PC came with a wopping 128k, or
512k! (640k being enough for anyone).


>> [] Thanks, sorry I didn't spot what you were doing; nice trick!
>
> No worries. I myself had trouble recognising your trick loading DX with
> 3030. Took a bit of time for the coin to drop. :-)
>
you could use a more comfortable 0x0A0D !

[]

R.Wieser

unread,
May 16, 2016, 6:32:49 AM5/16/16
to
Kerr,

> The original IBM PCjr had 64k, though the PC came with a
> wopping 128k, or 512k! (640k being enough for anyone).

The total ammount of memory is not the issue here.

The problem is that that memory could get fragmented, with memory slots of
varying sizes. If your program gets loaded into a fragmented memory block
of less than approx 3045 bytes you would be overwriting a program in the
next memory slot ...

> you could use a more comfortable 0x0A0D !

On a Windows machine where I can get a fresh commandline box with the press
of a button I would probably use the trick to win a contest. There would
however be a rather large chance that I would delete everything in regard to
it afterwards.

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhjth...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 16, 2016, 12:34:11 PM5/16/16
to
On Sun, 15 May 2016 15:47:51 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

> Kerr,
>
>> trick to save 1 byte in printing, and 1 by hardcoding the
>> Prtarea - I think you could use that 2nd one.
>
> Thats a rather nasty trick you're using there, putting the buffer in
> la-la
> land -- what happens when your code is loaded in a memory space just big
> enough for your code ?
>
> Hmmm ... I just realized that I also can't remember what happens with
> SP
> if a program is loaded in a some memory space smaller than 64 KB. Could
> be
> because the very first thing I always do is to load SP (most often to
> 0x0100) ...
>
> And a suggestion for improvement (taken from my own code): do not add a
> constant to SI, but take the CX register instead (saves exactly a single
> byte :-) ):


org 0x100 ; FizzBuzz MJ D - count up from -ve [ 67 ]
cpu 8086
; at start ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx
mov dx,Prtarea ; harded code dword [ 3 ]
eachnum: ; [ setup main 5 ]
mov di,dx ; reset to print next
mov si,Texttbl
nextFB: ; [ main 18 ]
mov cl,textlth ; reset for each Textstr
inc byte [si] ; count up: either FBcnt or TotalCnt
lodsw ; al=num, ah=reset ; si->text
jg dunallFB ; on TotalCnt
jnz notthisFB ; then skip Textstr to next
mov byte [si-2],ah ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
jmp nextFB

dunallFB: ; al is TotalCnt
cmp al,100 ; exit? [ 4 ]
jg exit
cmp dx,di ; if any FB found skip num [ 4 ]
jne goprt
aam ; cpynum [ 7 ]
or ax,dx ; to ascii num - hard code dx to 3030
xchg ah,al ; other endian
stosw ; with leading Z
goprt:
dec si ; addcrlf$ [ 3]
movsw ; add crlf
movsb ; add eos
mov ah,9 ; dos prtstr$ [ 4 ]
int 0x21
jmp short eachnum ; redo [ 3]
exit: ret

textlth equ 4
Texttbl: db -3,-3,"Fizz" ; [ tbl entries*6+1]
db -5,-5,"Buzz"
; db -7,-7,"Bang"
; db -11,-11,"Zapp"
TotalCnt db 0 ; aka endFB
Crlf db 0x0D,0x0A,'$' ; [ 3 ] ; must be next after TotalCnt

Prtarea equ 0x3030 ; hard coded dw

Robert Wessel

unread,
May 16, 2016, 3:34:32 PM5/16/16
to
On Mon, 16 May 2016 10:18:42 +0100, "Kerr Mudd-John"
<ad...@nospicedham.127.0.0.1> wrote:

>On Mon, 16 May 2016 08:19:22 +0100, R.Wieser
><add...@nospicedham.not.available> wrote:
>
>> Kerr,
>>
>>> I think you're allowed to assume a (small) stack on boot; it
>>> should be at FFFE in DOS
>>
>> Thats the problem, it assumes that your COM program has always *at
>> least* 64
>> KByte of memory allocated on load. Which I'm not all that sure of ...
>>
>
>The original IBM PCjr had 64k, though the PC came with a wopping 128k, or
>512k! (640k being enough for anyone).


You could order original PCs with as little as 16KB of memory,
although IIRC you needed at least 32KB to run PC-DOS 1.0 (and I think
PC-DOS 2.0 bumped that to 48KB).

Actually IBM shipped many PCs with only 16KB, with the vendors adding
non-IBM memory to whatever size customers wanted, as that was usually
significantly cheaper than official IBM memory.

Kerr Mudd-John

unread,
May 16, 2016, 4:34:39 PM5/16/16
to
On Mon, 16 May 2016 20:27:24 +0100, Robert Wessel
<robert...@nospicedham.yahoo.com> wrote:

> On Mon, 16 May 2016 10:18:42 +0100, "Kerr Mudd-John"
> <ad...@nospicedham.127.0.0.1> wrote:
>
[]
>>
>> The original IBM PCjr had 64k, though the PC came with a wopping 128k,
>> or
>> 512k! (640k being enough for anyone).
>
>
> You could order original PCs with as little as 16KB of memory,
> although IIRC you needed at least 32KB to run PC-DOS 1.0 (and I think
> PC-DOS 2.0 bumped that to 48KB).
>
> Actually IBM shipped many PCs with only 16KB, with the vendors adding
> non-IBM memory to whatever size customers wanted, as that was usually
> significantly cheaper than official IBM memory.

Sorry, ISCWF

I shudda checked wikipedia 1st.

Kerr Mudd-John

unread,
May 17, 2016, 5:06:57 AM5/17/16
to
On Mon, 16 May 2016 17:24:23 +0100, Kerr Mudd-John
<ad...@nospicedham.127.0.0.1> wrote:

[]
> org 0x100 ; FizzBuzz MJ D - count up from -ve [ 67 ]
[]
org 0x100 ; FizzBuzz MJ E [ 66 ]
cpu 8086
; at start ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx
mov dx,Prtarea ; harded code dword [ 5 ]
mov bl,100
eachnum: ; -setup main- [ 5 ]
mov di,dx ; reset to print next
mov si,Texttbl
nextFB: ; -main- [ 18 ]
mov cl,textlth ; reset for each Textstr
inc byte [si] ; count up: either FBcnt or TotalCnt
lodsw ; al=num, ah=reset ; si->text
jg dunallFB ; on TotalCnt
jnz notthisFB ; then skip Textstr to next
mov byte [si-2],ah ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
jmp nextFB ; -end main- ---

dunallFB: ; al is TotalCnt ah =0
cmp dx,di ; if any FB set, skip num [ 4 ]
jne goprt
aam ; -cpynum- [ 7 ]
or ax,dx ; to ascii num - hard code dx to 3030
xchg ah,al ; other endian
stosw ; with leading Z
goprt:
movsw ; -cpy crlf$- [ 2 ]
movsb ; add eos
mov ah,9 ; -dos prtstr$- [ 4 ]
int 0x21
dec bx ; -chk end- [ 3 ]
jg eachnum
exit: ret ; [ 1 ]

textlth equ 4
Texttbl: db -3,-3,"Fizz" ; (tbl entries=2)*6 [ 12 ]
db -5,-5,"Buzz"
; db -7,-7,"Bang"
; db -11,-11,"Zapp"
TotalCnt dw 0 ; endFB [ 2 ]
Crlf db 0x0D,0x0A,'$' ; must be next after TotalCnt [ 3 ]

Prtarea equ 0x3030 ; hard coded dw total [*66*]


I think that's as low as I can go!

R.Wieser

unread,
May 17, 2016, 9:37:25 AM5/17/16
to
Kerr,

> I think that's as low as I can go!

If you hard-code the 'zz'-s (and by it limit yourself to just "Fizz" and
"buzz" again) you can shave off another byte ...

- - - - - - - - - - - - - - - - - - - -
nextFB:
dec byte ptr [si] ; count down
jl dunallFB ; terminating 0 goes -ve, and keeps -ve

lodsw ; al=num, ah=reset ; si->text
xchg cx,ax ;Save reset value
lodsw ;Preload "Fi" or "Bu"
jnz nextFB ; Go do next entry

mov byte ptr [si-4],ch ; reset count
stosw ;Write either "Fi" or "Bu"
mov ax,'zz' ;Write the last two chars
stosw
jmp nextFB
- - - - - - -

Texttbl db 3,3,"Fi"
db 5,5,"Bu"

- - - - - - - - - - - - - - - - - - - -

Regards,
Rudy Wieser


- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhlmz...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 17, 2016, 12:53:07 PM5/17/16
to
On Tue, 17 May 2016 14:25:33 +0100, R.Wieser
<add...@nospicedham.not.available> wrote:

> Kerr,
>
>> I think that's as low as I can go!
>
> If you hard-code the 'zz'-s (and by it limit yourself to just "Fizz" and
> "buzz" again) you can shave off another byte ...
>

Thanks, but no. It wouldn't be a generalised solution then. I'm revisiting
a BCD version, but that's still at 71 bytes.

> - - - - - - - - - - - - - - - - - - - -
> nextFB:
> dec byte ptr [si] ; count down
> jl dunallFB ; terminating 0 goes -ve, and keeps -ve
>
> lodsw ; al=num, ah=reset ; si->text
> xchg cx,ax ;Save reset value
> lodsw ;Preload "Fi" or "Bu"
> jnz nextFB ; Go do next entry
>
> mov byte ptr [si-4],ch ; reset count
> stosw ;Write either "Fi" or "Bu"
> mov ax,'zz' ;Write the last two chars
> stosw
> jmp nextFB
> - - - - - - -
>
> Texttbl db 3,3,"Fi"
> db 5,5,"Bu"
>



R.Wieser

unread,
May 17, 2016, 4:38:32 PM5/17/16
to
Kerr,

> Thanks, but no. It wouldn't be a generalised solution then.

Yes, that would be the drawback, a sacrifice to get the lowest possible
bytecount.

On the other hand, if you would have wanted that you would probably have
continued to perfect your two stosw's approach .

Regards,
Rudy Wieser


-- Origional message:
Kerr Mudd-John <ad...@nospicedham.127.0.0.1> schreef in berichtnieuws
op.yhl8r...@dell3100.dlink.com...

Kerr Mudd-John

unread,
May 18, 2016, 5:27:26 PM5/18/16
to
On Tue, 17 May 2016 09:53:33 +0100, Kerr Mudd-John
Yup; here's the BCD version (2 more)
org 0x100 ; FizzBuzz MJ F BCD [ 68 ]
cpu 8086
start: ; ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx
; prog assumes ch=bh=0, mem available at 0x3030
mov dx,Prtarea ; harded code dword [ 5 ]
mov bl,100 ; BCD tops out here
eachnum: ; -setup main- [ 5 ]
mov di,dx ; reset to print next
mov si,Texttbl
; @@@ rearranged; but can't avoid a jmp : ldz code no smaller @@@
jmp short nextFB ; [ 18 ]
isFB:
mov byte [si-2],ah ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
nextFB:
mov cl,textlth ; reset for each Textstr
inc byte [si] ; count up: either FBcnt or TotalCnt
lodsw ; al=num, ah=reset ; si->text
jz isFB
jng notthisFB ; then skip Textstr to next
; jg dunallFB ; on TotalCnt
dunallFB: ; ax is TotalCnt in BCD
aaa ; adjust if >'9' [ 4 ]
mov [si-2],ax ; update
nottens:
cmp dx,di ; if any FB set, skip num [ 4 ]
jne goprt
or ax,dx ; cpynum with ldz [ 5 ]
xchg ah,al
stosw
goprt:
movsw ; -cpycrlf$- [ 2 ]
movsb ; add eos
mov ah,9 ; -dos prtstr$- [ 4 ]
int 0x21
dec bx ; -chk end- [ 3 ]
jg eachnum
exit: ret ; [ 1 ]

textlth equ 4
Texttbl: db -3,-3,"Fizz" ; (tbl entries=2)*6 [ 12 ]
db -5,-5,"Buzz"
; db -7,-7,"Bang"
; db -11,-11,"Zapp"
TotalCnt dw 0 ; endFB [ 2 ]
Crlf db 0x0D,0x0A,'$' ; must be next after TotalCnt [ 3 ]
proglth equ $-start
Prtarea equ 0x3030 ; hard coded dw total [*68*]

Kerr Mudd-John

unread,
May 20, 2016, 5:02:33 PM5/20/16
to
On Wed, 18 May 2016 22:22:24 +0100, Kerr Mudd-John
<ad...@nospicedham.127.0.0.1> wrote:

> On Tue, 17 May 2016 09:53:33 +0100, Kerr Mudd-John
> <ad...@nospicedham.127.0.0.1> wrote:
>
>> On Mon, 16 May 2016 17:24:23 +0100, Kerr Mudd-John
>> <ad...@nospicedham.127.0.0.1> wrote:
>>
>> []
>>> org 0x100 ; FizzBuzz MJ D - count up from -ve [ 67
>>> ]
>> []
>> org 0x100 ; FizzBuzz MJ E [ 66 ]

org 0x100 ; FizzBuzz MJ K [ 64 ]
cpu 8086 ;
start: ; ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx nz
; prog assumes ch=bh=0, mem available at 0x3030
mov dx,Prtarea ; harded code dword [ 5 ]
mov bl,100 ; 100 tops for prt; assume nz 1st
eachnum: ; -setup main- [ 5 ]
mov di,dx ; reset to print next
mov si,Texttbl-textlth ; fixup for fallthru 1st time
nextFB: ; -main- [ 16 ]
mov cl,textlth ; reset for each Textstr
jnz notthisFB ; then skip Textstr to next
mov byte [si-2],ah ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
inc byte [si] ; count up: either FBcnt or TotalCnt
lodsw ; al=num, ah=reset ; si->text
jng nextFB ; Afterward al=TotalCnt, si->crlf$
cmp dx,di ; if any FB set, skip num [ 4 ]
jne goprt
aam ; -cpynum- [ 7 ]
xchg ah,al ; other endian
or ax,dx ; 2 digit ascii num; dx=0x3030
stosw ; with leading Z
goprt:
movsw ; -cpycrlf$- [ 2 ]
movsb ; add eos
mov ah,9 ; -dos prtstr$- [ 4 ]
int 0x21
dec bx ; -chk end- [ 3 ]
jg eachnum ; nz flag set
exit: ret ; [ 1 ]

textlth equ 4
Texttbl db -3,-3,"Fizz" ; (tbl entries=2)*6 [ 12 ]
db -5,-5,"Buzz"
; db -7,-7,"Bang"
; db -11,-11,"Zapp"
TotalCnt dw 0 ; endFB [ 2 ]
Crlf db 0x0D,0x0A,'$' ; must be next after TotalCnt [ 3 ]
proglth equ $-start
Prtarea equ 0x3030 ; hard coded dw total [*64*]

Kerr Mudd-John

unread,
Jun 9, 2016, 4:43:28 AM6/9/16
to
On Fri, 20 May 2016 21:57:50 +0100, Kerr Mudd-John
<ad...@nospicedham.127.0.0.1> wrote:

> On Wed, 18 May 2016 22:22:24 +0100, Kerr Mudd-John
> <ad...@nospicedham.127.0.0.1> wrote:
>
>> On Tue, 17 May 2016 09:53:33 +0100, Kerr Mudd-John
>> <ad...@nospicedham.127.0.0.1> wrote:
>>
>>> On Mon, 16 May 2016 17:24:23 +0100, Kerr Mudd-John
>>> <ad...@nospicedham.127.0.0.1> wrote:
>>>
>>> []
>>>> org 0x100 ; FizzBuzz MJ D - count up from -ve [
>>>> 67 ]
>>> []
>>> org 0x100 ; FizzBuzz MJ E [ 66 ]
>
> org 0x100 ; FizzBuzz MJ K [ 64 ]
[]
org 0x100 ; FizzBuzz MJ R [ 63 ]

Kerr Mudd-John

unread,
Jun 15, 2016, 2:50:27 PM6/15/16
to
On Fri, 20 May 2016 21:57:50 +0100, Kerr Mudd-John
<ad...@nospicedham.127.0.0.1> wrote:

> On Wed, 18 May 2016 22:22:24 +0100, Kerr Mudd-John
> <ad...@nospicedham.127.0.0.1> wrote:
>
>> On Tue, 17 May 2016 09:53:33 +0100, Kerr Mudd-John
>> <ad...@nospicedham.127.0.0.1> wrote:
>>
>>> On Mon, 16 May 2016 17:24:23 +0100, Kerr Mudd-John
>>> <ad...@nospicedham.127.0.0.1> wrote:
>>>
>>> []
>>>> org 0x100 ; FizzBuzz MJ D - count up from -ve [
>>>> 67 ]
>>> []
>>> org 0x100 ; FizzBuzz MJ E [ 66 ]
>
> org 0x100 ; FizzBuzz MJ K [ 64 ]

with variable length Fizz Buzz Zap Pingit!

org 0x100 ; FizzBuzz MJ Y [ 67 ]
cpu 8086 ; added variable str lth: +4
start: ; ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx nz
; prog assumes ch=0, mem available at 0x3030, nz at start
mov dx,Prtarea ; harded code dword [ 3 ]
eachnum: ; -setup main- [ 5 ]
mov di,dx ; reset to print next
mov si,FBtbl-1
nextFB: ; -main- [ 17 ]
lodsb ; get textlth
mov cl,al
jnz notthisFB ; then skip Textstr to next
mov byte [si-3],ah ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
eachFB:
inc byte [si] ; count up: either FBcnt or TotalCnt
lodsw ; FB:al=num, ah=reset, si->Textstr
jng nextFB ; TC:al=TotalCnt,ah=09,si->crlf$
cmp dx,di ; -skip num if FB- [ 4 ]
jne goprt
push ax ; save TotalCnt/Dosprtstr
aam ; -cpynum- [ 9 ]
xchg ah,al ; other endian; div costs more
or ax,dx ; 2 digit ascii num; dx=0x3030
stosw ; with leading Z
pop ax ; restore TotalCnt/Dosprtstr
goprt:
movsw ; -cpycrlf$- [ 2 ]
movsb ; add eos
cmp al,100 ; - end/ prt- max 100 [ 7 ]
int 0x21 ; flags preserved!
jl eachnum ; nz from cmp
exit: ret
addzr db 0 ; cheaper than jmp
FBtbl db -3,-3,4,"Fizz" ; variable lth, but for FB - [ 15 ]
db -5,-5,4,"Buzz" ; cnt,reset,lth,str
; db -7,-7,3,"Zap"
; db -11,-11,7,"Pingit!"
TotalCnt db 0 ; endFB [ 2 ]
Dosprtstr db 0x09 ; loaded
Crlf db 0x0D,0x0A,'$' ; [ 3 ]
proglth equ $-start
Prtarea equ 0x3030 ; hard coded dw total [*67*]

Kerr Mudd-John

unread,
Jan 10, 2017, 12:15:22 PM1/10/17
to
On Wed, 15 Jun 2016 17:36:21 -0100, Kerr Mudd-John
<ad...@nospicedham.127.0.0.1> wrote:

[]
>
> with variable length Fizz Buzz Zap Pingit!
>
> org 0x100 ; FizzBuzz MJ Y [ 67 ]

2 less:

org 0x100 ; FizzBuzz MJ mvY [ 65 ]
cpu 8086 ; variable str lth: only lth cost!
start: ; ax=0 bx=0 cx=00xx dx=cs=ds=es=xxxx si=0100 di=sp=FFFE bp=09xx nz
; prog assumes ch=0, mem available at 0x3030, nz at start
mov dx,Prtarea ; harded code dword [ 3 ]
eachnum: ; -setup main- [ 5 ]
mov di,dx ; reset to print next
mov si,loadamt ; get to FBtbl @0x2F: init 0x25
nextFB: ; -main- [ 17 ]
lodsw ; get textlth & reset - keep flags!
mov cl,ah ; initial 9(+26) for fallthru
jnz notthisFB ; then skip Textstr to next
iszero: mov byte [si-3],al ; have a FB, reset count
repnz movsb ; cpy Textstr
notthisFB:
add si,cx ; add 0 if moved, or textlth to skip.
eachFB: inc byte [si] ; count up: either FBcnt or TotalCnt
lodsb ; FB:al=num, si->Textstr
jng nextFB ; TC:al=TotalCnt,si->crlf$
isnum: aam ; -cpynum- [ 11 ]
xchg ah,al ; other endian; div costs more
or ax,dx ; 2 digit ascii num; dx=0x3030
cmp dx,di ; skip num if FB
jne goprt
stosw ; with leading Z
goprt:
mov ah,9 ; 9 + off25 = 2E,+1=0x2F [ 11 ]
loadamt equ $-2 ; hard coded offset needed to get FBtbl
movsw ; cpy crlf
movsb ; cpy eos
cmp al,0x30+10 ; 3A ends max 100 (2 digit)
int 0x21 ; flags preserved!
jl eachnum ; nz from cmp
exit: ret
;; 0x2F
FBtbl db -3,-3,3,"Fiz" ; variable lth, but for FB - [ 14 ]
db -5,-5,5,"Buzz!" ; cnt,reset,lth,Textstr
; db -7,-7,3,"Zap"
; db -11,-11,7,"Pingit!"
TotalCnt db 0,0x0D,0x0A,'$' ; [ 4 ]
proglth equ $-start
Prtarea equ 0x3030 ; hard coded dw total [*65*]
0 new messages