# Another atempt at MSX ASM programming

Page 1/3
| 2 | 3

Hello,

I decided to do another try on MSX ASM programming. I did a first atempt years ago and I didn't get far (I just went beyond the Hello World and even put some sprites on the screen). I'm not new to programming, I make a living from it, but only using high level languages, and I think I need to do some serious ASM coding.

The books / tutorial I see put much effort in learning the Z80, VDP and other stuff, and altough they are not wrong, I miss examples of doing simple things in ASM in a MSX machine, like asking the user to enter 2 numbers, and the program would add those two numbers and print the results to the user. In this process it could be explained how to do that using BIOS or BDOS calls, and how to deal with bigger numbers than 255.

Anyone can show me such example (asking the user 2 numbers, storing those numbers in memory, and then adding and print the results to the user) ?

Btw, if someone can point me to a book / tutorial / whatever that shows how to write small ASM MSX programs that do some simple math (reading numbers / multiply and divide numbers/ storing numbers in arrays and processing those numbers, fatorial etc), it would be a great help.

You are on the right track. Programming in assembly means breaking up your code in many small pieces that perform a specific task. You have named them correctly.

Numbers are a tricky thing though. We humans use a decimal system, where the computer will store it for example as a 16-bit integer. Your routine will need to verify whether the input is valid, parse it and store it. For simplicity you can initially skip the verification process.

Sorry, but I don't have routines at hand. Probably others can help you with that. But to kick you off, here's a simple example to input 2 numbers in MSX-DOS.

```bdos:           equ     0x0005
string_out:     equ     0x09
buffer_input:   equ     0x0a

org     0x0100

ld      de, message1
ld      c, string_out
call    bdos

ld      a, 5
ld      de, buffer
ld      (de),a
ld      c, buffer_input
call    bdos

ld      de, crlf
ld      c, string_out
call    bdos

; verify and parse input

ld      de, message2
ld      c, string_out
call    bdos

ld      a, 5
ld      de, buffer
ld      (de),a
ld      c, buffer_input
call    bdos

ld      de, crlf
ld      c, string_out
call    bdos

; verify and parse input

ret

message1:       db      'Enter first number: \$'
message2:       db      'Enter second number: \$'
crlf:           db      0x0d, 0x0a, '\$'
buffer:         ds      0x07, 0x00```

Thanks a lot Briqunullus!

I'll try your code as soon as I get home, and see what I can do with it.

I did a bit of experimenting myself. I couldn't find a routine to parse ascii string to int, so I came up with one. There will always be more efficient ways to do this, but that's how assembly works. Start with the basics and optimize if your skills grow. Routine to print an integer has been taken from here.

```bdos:           equ     0x0005
string_out:     equ     0x09
buffer_input:   equ     0x0a

org     0x0100

ld      de, message1
ld      c, string_out
call    bdos

ld      a, 5
ld      de, buffer
ld      (de),a
ld      c, buffer_input
call    bdos

ld      de, crlf
ld      c, string_out
call    bdos

ld      a, (buffer + 1)
cp      5
jr      nz, no_full_buffer
ld      a, 0x0d
ld      (buffer + 7),a

no_full_buffer: ld      de, buffer + 2
call    parse_int
ld      (number1), hl

ld      de, message2
ld      c, string_out
call    bdos

ld      a, 5
ld      de, buffer
ld      (de),a
ld      c, buffer_input
call    bdos

ld      de, crlf
ld      c, string_out
call    bdos

ld      a, (buffer + 1)
cp      5
jr      nz, no_full_buffer2
ld      a, 0x0d
ld      (buffer + 7),a

no_full_buffer2:ld      de, buffer + 2
call    parse_int
ld      (number2), hl

ld      de, message3
ld      c, string_out
call    bdos

ld      hl, (number1)
ld      de, (number2)

ld      de, output_buffer
call    num2dec

ld      a, '\$'
ld      (de), a

ld      de, output_buffer
ld      c, string_out
call    bdos

ret

parse_int:      ld      hl, 0
next_digit:     ld      a, (de)
cp      0x0d                    ; end of input
ret     z

sub     '0'                     ; accept numbers only
ret     c
cp      10
ret     nc

call    hl_times_10

inc     h
inc     de
jr      next_digit

hl_times_10:    ld      c,l
ld      b,h
ret

num2dec:        ld  bc,-10000
call    num1
ld  bc,-1000
call    num1
ld  bc,-100
call    num1
ld  c,-10
call    num1
ld  c,b

num1:           ld  a,'0'-1
num2:           inc a
jr  c,num2
sbc hl,bc

ld  (de),a
inc de
ret

message1:       db      'Enter first number: \$'
message2:       db      'Enter second number: \$'
message3:       db      'Sum of numbers: \$'
crlf:           db      0x0d, 0x0a, '\$'

buffer:         ds      0x08, 0x00

number1:        dw      0x0000
number2:        dw      0x0000

output_buffer:  ds      0x06, 0x00```

Maybe fo this specific case, you should use BCD code.
Also, I would recommend MSX Pen for this kind of experiments, as it fits perfectly.

Yes, that's precisely the problem. Assembler does not have high-level functions like C/Java for getting input from the user (e.g., decimal numbers), and then writing it back to screen. So, those examples are trickier. That's why usually tutorials go quickly to the VDP, etc. As that is easier

Writing an input routine from scratch that then converts the numbers from decimal strings to binary, and then converting back from binary to decimal strings is a good exercise though!

I always have the feeling: why reinvent the wheel for such dull and always repeating tasks?

It would be great if there would be some common assembler library with all kinds of super-optimized generically applicable routines. So, you just get the best (general) solution and don't have to think it over. And instead, you can focus on the specific problems for your application.
I don't think such a library exist, does it?

A good alternative is to use C and write performance critical stuff in assembler, like several people are doing nowadays already. But also there, it would be good to have optimized routines for stuff like reading joystick input or collision detection or whatever. (I think Fusion-C is partly fulfilling that, isn't it?)

Do other people have the same feeling? (Perhaps it's just me?)

The high-level functions, and the common library, is the BIOS.

I agree with Grauw. And reinvent the wheel is useful to improve coding skills.

Manuel wrote:

I always have the feeling: why reinvent the wheel for such dull and always repeating tasks?

It would be great if there would be some common assembler library with all kinds of super-optimized generically applicable routines. So, you just get the best (general) solution and don't have to think it over. And instead, you can focus on the specific problems for your application.
I don't think such a library exist, does it?

A good alternative is to use C and write performance critical stuff in assembler, like several people are doing nowadays already. But also there, it would be good to have optimized routines for stuff like reading joystick input or collision detection or whatever. (I think Fusion-C is partly fulfilling that, isn't it?)

Do other people have the same feeling? (Perhaps it's just me?)

I respectfully disagree... Perhaps, thinking on a higher level, a machine that can index memory and work with stack more efficiently than msx/z80, I would agree with you... But on MSX, the reason to go ASM instead of C or Pascal is pure performance or smaller footprint, and then you have generic libraries in ASM, those aren't going to cut it performance wise... I.e.: you might get a behemoth function that is generic to adress converting numbers to ASCII text string, well that function will need to open up to several cases, leading 0s? Which base? 8,16 32 bits? This increases size and decrease efficiency...

But, I'm against reinventing the wheel and there are several good places to learn optimized ASM routines, Grauw's excellent MAP is one of my favourites, but there is plenty of gold to be found on CPC, ZX and other communities that also use a computer wit z80.

To me, the best way to learn ASM is to get some program you like, that the code is available, and give yourself a few tasks to improve or add doable small things... To do that you will look into the code, understand how it works, what and why it does, and by then, learned a lot. Also this is the reason I'm excessively verbose on commenting my code, I just like to think that by being clear on the intention on every little piece of the code, two benefits will come true:

1 - People will be able to learn from it
2 - By being clear on the intention and what is expected, people can more easily contribute with changes and improvements, where I'm the one learning other ideas and methods

So, I don't think generic ASM libraries are evil, just that I think those should be used wisely and mostly to extract and create your own optimized version that suits your needs and do not waste space or cycles unnecessarily, they might help at first, to get your feet wet, but at some point in time, at least msx wise, you'll need to be working on those to get better results.

Page 1/3
| 2 | 3