Another atempt at MSX ASM programming

Page 2/3
1 | | 3

Par Manuel

Ascended (17341)

Portrait de Manuel

01-10-2020, 07:40

Grauw wrote:

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

Is it sufficiently optimised?
Does it have enough functionality?

Par Briqunullus

Champion (267)

Portrait de Briqunullus

01-10-2020, 09:08

Libraries, optimization and a thousand different ways of doing one thing are all integral part of assembly programming. However, this guy is new to the trade, so let's start with the basics please. Smile

He has a specific case in mind, we provide him with a working example (just one way of doing it), he tries to break it down and learns from it. Then he reads the suggestion about BCD, looks into that, and rewrites the example himself. And before we know it, a new shmup will arrive in 2022...

Par Grauw

Ascended (9501)

Portrait de Grauw

01-10-2020, 10:45

As an advanced programmer I wouldn’t use a library of someone else. I could imagine copy / pasting code snippets, but then making it my own. In the end decisions about size and speed and parameters etc. are often made based on context, and I don’t think this can be fully captured by a general library.

As a beginning programmer, firstly in order to use a library one needs to be made available and maintained, and I mean I share all my code but I have no interest in turning it into a general purpose library, and I think that goes for most advanced programmers. Second as people already expressed, actually it is a very good programming exercise to write e.g. a routine that prints a decimal number.

I think if anything, having articles that show and explain common routines (like there are some present on the MAP) is more useful to the beginner programmer than an opaque library of obscurely-written (because: optimised) code. On that note, if there is a particular programming problem / routine missing that someone would like to read more about, I am open to suggestions.

Par pgimeno

Master (253)

Portrait de pgimeno

01-10-2020, 16:24

iamweasel2 wrote:

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.

Something I think should be mentioned, and haven't seen mentioned so far, is that in assembler these are not simple things.

In Z80 assembler, you don't have expressions beyond assignments, additions and subtractions. You don't even have multiplication (except in the R800) or division, for example.

Also, unlike in a high level language, an input from the user requires access to peripherals. This may be already provided by the BIOS or BDOS, though.

Converting a number from the ASCII digits to the value that finally goes in a register requires an algorithm that isn't too simple either. It involves multiplication by 10, and as I said, there's no built-in multiplication (even if there are tricks). Conversely, translating from a register to ASCII requires division, which is even worse. In a high level language, these conversions are provided by ready-made routines.

A much simpler program would be one that adds two fixed-size series of ASCII digits pre-loaded in a certain memory area, and stores the result in some other memory area, WITHOUT intermediate conversion to registers. This implies that the addition is done on the ASCII digits directly. Someone suggested BCD, but that's an unnecessary extra complication.

I've seen this method frequently used to handle scores in games.

Here's some code to do just that. For clarity, I have not optimized it.

Note: This code doesn't assemble correctly with Glass, you can use Pasmo instead.

; Add two 8-digit numbers into another 8-digit number
		org	0B000h

NumberLen	equ	8

AddTwoNumbers:	ld	bc,Number1+NumberLen
		ld	hl,Number2+NumberLen
		ld	de,Result+NumberLen

		ld	ix,Carry
		ld	(ix+0),0	; clear carry the first time
AddLoop:	dec	bc
		dec	hl
		ld	a,(bc)
		add	a,(hl)		; we're adding the ASCII of '0' twice
		sub	'0'		; subtract it once
		add	a,(ix+0)	; add carry

		cp	'9'+1		; have we exceeded the range of a digit?
		jr	nc,Exceeded	; if so, jump to Exceeded
		ld	(ix+0),0	; no carry on this branch
StoreDigit:
		dec	de
		ld	(de),a
		ld	a,e		; Compare the low part of DE
		cp	LOW Result
		jr	nz,AddLoop
		ld	a,d		; This part of the comparison is not
		cp	HIGH Result	; actually necessary because it will
		jr	nz,AddLoop	; always be equal, but the code is easier
		ret			; to understand with it
Exceeded:
		ld	(ix+0),1	; carry
		sub	10		; adjust digit to remove excess
		jr	StoreDigit

Carry		db	0

		org	0B400h
Number1		db	'00987654'

		org	0B500h
Number2		db	'00031415'

		org	0B600h
Result		db	'00000000'

You could use this BASIC program to display the result:

10 FOR N=&HB600 TO &HB607:PRINT CHR$(PEEK(N));:NEXT N

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 19:25

Thank you all for your input, it has been most valuable.

I started writing some code, just to get things going. It works fine, although it is of course not optimized yet:

CHPUT: equ 0x00a2 ; prints 1 caracter on screen
CLS: equ 0x00c3
CHGET equ 0x009F ; One character input (waiting). Output: A - ASCII code of the input character
; the address of our program

org 0xD000

start:
xor a
call CLS ; clear screen

ld hl, NOMEDOPRG
call printMessage

ld hl, AUTOR
call printMessage

ld hl, PERGUNTA
call printMessage

call CHGET
LD (VAR1),A

ld hl, RESP1
call printMessage

LD A,(VAR1)
call CHPUT ; print caracter typed by the user.

ret

printMessage: ld a, (hl)
cp 0
ret z
call CHPUT
inc hl
jr printMessage

message: db "Ola Mundo 3!",13,10,10,0
NOMEDOPRG: DB "Program Number 2",13,10,10,0
AUTOR: DB "interacting with user",13,10,10,0
PERGUNTA: DB "Press any key:",0
RESP1: DB 13,10,10," The key pressed was: ",0
VAR1: DB 0

; use the label "start" as the entry point
end start

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 19:27

The program above works well, and the next step would be to get an entire string from the user. I saw that in BIOS we could use PINLIN function to do that (reading a String typed by the user).

My question is, how to use that function? Where it writes the caracters typed by the user?

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 20:06

.

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 20:05

.

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 20:05

[ERASED] .

Par iamweasel2

Paladin (667)

Portrait de iamweasel2

01-10-2020, 20:04

I think I got it right this time, at least it is working correctly now:

CHPUT: equ 0x00a2 ; prints 1 caracter on screen
CLS: equ 0x00c3
CHGET equ 0x009F ; One character input (waiting). Output: A - ASCII code of the input character
PINLIN equ 0x00AE
; the address of our program

org 0xD000

start:
xor a
call CLS ; clear screen

ld hl, PROGRAMNAME
call printMessage

ld hl, AUTOR
call printMessage

ld hl, QUESTION
call printMessage

call PINLIN

ld (VAR1),HL
ld hl, RESP1
call printMessage

ld HL, (VAR1)
call printMessage

ret

printMessage: ld a, (hl)
cp 0
ret z
call CHPUT
inc hl
jr printMessage

PROGRAMNAME: DB "Program Number 2",13,10,10,0
AUTOR: DB "interacting with user",13,10,10,0
QUESTION: DB "Type your text:",0
RESP1: DB 13,10,10," The text you typed was: ",0
VAR1: DB 0,0

; use the label "start" as the entry point
end start

Page 2/3
1 | | 3