Another atempt at MSX ASM programming

Page 1/3
| 2 | 3

By iamweasel2

Hero (604)

iamweasel2's picture

30-09-2020, 17:44

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) ?

Login or register to post comments

By iamweasel2

Hero (604)

iamweasel2's picture

30-09-2020, 17:48

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. Smile

By Briqunullus

Master (174)

Briqunullus's picture

30-09-2020, 18:45

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
                ; add code here
                
                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
                ; add code here

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

By iamweasel2

Hero (604)

iamweasel2's picture

30-09-2020, 19:21

Thanks a lot Briqunullus! Smile

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

By Briqunullus

Master (174)

Briqunullus's picture

30-09-2020, 20:42

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)
                add     hl, de
                
                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
                
                add     a, l
                jr      nc, add_done
                inc     h
add_done:       ld      l, a
                inc     de
                jr      next_digit              
                
hl_times_10:    ld      c,l
                ld      b,h
                add     hl, hl
                add     hl, hl
                add     hl, bc
                add     hl, hl
                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
                add hl,bc
                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

By albs_br

Master (146)

albs_br's picture

30-09-2020, 22:29

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.

By santiontanon

Paragon (1092)

santiontanon's picture

30-09-2020, 23:29

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 Smile

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!

By Manuel

Ascended (16961)

Manuel's picture

30-09-2020, 23:35

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?)

By Grauw

Ascended (9337)

Grauw's picture

01-10-2020, 00:30

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

By thegeps

Hero (555)

thegeps's picture

01-10-2020, 00:41

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

By ducasp

Champion (366)

ducasp's picture

01-10-2020, 02:03

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. Smile

Page 1/3
| 2 | 3