How to use MSX-DOS2 memory mapper routines?

Page 1/2
| 2

By DarkSchneider

Paladin (965)

DarkSchneider's picture

24-12-2016, 17:19

I am reading the documentation here but not sure to understand completely how to use them.

Could be something like the following? I.e. for calling ALL_SEG:

- Get mapper support routine address:
set A = 0, D = 4, E = 2. With this I suppose the memory mapper device for extended BIOS has assigned number 4, and 2 is the function to get the support routine address.
CALL EXTBIO. EXTBIO is FFCAh.
HL = mapper support routine address
mapper_routines = HL. Save value.

- Calling ALL_SEG:
all_seg = mapper_routines + 0h. Looking at table definition: +0H ALL_SEG Allocate a 16k segment.
For user segment:
set A = 0, B = 0. On primary mapper, the easy way ;)
CALL (all_seg)
Check result values, in this case the carry and A register.

Is this OK or am I doing it wrong?

Thanks.

Login or register to post comments

By zeilemaker54

Champion (345)

zeilemaker54's picture

24-12-2016, 17:49

Looks ok to me
If the carry flag is set, it means there are now free segments

By DarkSchneider

Paladin (965)

DarkSchneider's picture

24-12-2016, 18:32

Ok my main doubt was calling a function directly, instead as usual doing an indirect call (like calls to DOS with "CALL 5") or inter-slot calls like with other devices (like OPLL).

I suppose the DOS2 loads these functions in RAM at page 3 and calling them they do all the work involving bank switching (as DOS2 uses 2 segments for itself) and etc.

By zeilemaker54

Champion (345)

zeilemaker54's picture

24-12-2016, 19:03

Yes, the routines are in page3. The reason they are directly callable is probebly due speed reasons.

By DarkSchneider

Paladin (965)

DarkSchneider's picture

26-12-2016, 12:48

I am confused about the CALLS one:

Quote:

CALLS - Parameters: AF, BC, DE, HL passed to called routine
Other registers corrupted
Calling sequence: CALL CALLS
DB SEGMENT
DW ADDRESS
Results: AF, BC, DE, HL, IX and IY returned from called routine. All others corrupted.

But, we can't:
CALL CALLS
Because we have to get the instruction address first, so we have to use indirect calling using JP (HL, IX or IY). Then, where have to put SEGMENT and ADDRESS? Just after the 'JP ()' or the CALL that uses 'JP ()'?

I think it must the the 2nd one (the call that uses JP()), because probably it takes the SEGMENT and ADDRESS from PC+1 and PC+2, being PC the one stored in the stack by the CALL.

By Grauw

Ascended (10699)

Grauw's picture

26-12-2016, 13:47

Some example code, maybe useful.

https://bitbucket.org/grauw/vgmplay-msx/src/42dbb9b705/src/M...

I have a jump table which I fill during initialisation, then throughout my code I use this jump table which is at a compile-time fixed address, rather than doing indirect calls. One could fill it with all the addresses of the DOS2 jump table entries, but actually I just copy the whole DOS2 jump table on top of my own to save the additional jump.

(Implementing a DOS1 compatibility layer would also be fairly easy this way, although I haven’t.)

Btw be sure to restore the mapper pages and slots to their initial values on program termination. The DOS2 manual says it does this automatically, but it doesn’t, and it gets confused when the next program is executed.

By DarkSchneider

Paladin (965)

DarkSchneider's picture

26-12-2016, 13:54

Seems good. Copying the mapper jump tables to a local one. I currently only store the table start address and then put on HL, IX or IY (tableadr + function_offset), and then JP () directly or using an auxiliar function doing the JP(). This was to preserve the table on page 3. But I suppose if the mapper code is executing the table copy would also be available in any case, only taking care it does not get between 2 pages.
I will change to that method that looks better.

By Grauw

Ascended (10699)

Grauw's picture

26-12-2016, 14:26

Would’ve been so nice if the Z80 had support for indexed jumps… Seems logical to be there, but no.

By DarkSchneider

Paladin (965)

DarkSchneider's picture

26-12-2016, 16:51

All working but executing code from another segment. Tried both inter-segment and putting with putph and putp2.
Extracted the function address from the linker symbols file (and done right). Loaded the binary in a reserved segment, checked and the content is right there in the segment.
But when cal_seg or putph/putp2 and calling the function, it doesn't work. It freezes.
Using the page 2 to allocate the binary and program on page 0, so they don't overlap. The function is an empty one, to avoid dependencies failure. Here the ASM code of the program loaded into segment:

;	MSX-C ver 1.20p   (code generator)

	cseg

func01:
	ret


main@:
	ret


	public	func01
	public	main@

	end

The func01 is at 0x8028 but when calling, freeze.

By DarkSchneider

Paladin (965)

DarkSchneider's picture

28-12-2016, 10:26

Is CAL_SEG wrong? I have working CALLS, but CAL_SEG gets me a "DI, HALT detected" on openMSX.

Here is the function:

; BYTE calseg(TYPE arg1, TYPE arg2, TYPE arg3, UINT16 address, BYTE segment)
; pass always 5 parameters
calseg@:
	exx ; preserve parameters
	ld hl, 2
	add hl, sp ; hl = *address
	ld c, (hl)
	inc hl
	ld b, (hl)
	ld ix, 0
	add ix, bc
	inc hl ; hl = *segment
	ld c, (hl)
	ld b, 0
	ld iy, 0
	add iy, bc
	exx ; restore parameters
	jp _calseg

_calseg is the local copy of MSX-DOS2 table jump.
Declaration for MSX-C calling convention, so we have 3 parameters in registers, and then address and segment in the stack. These are read correctly, the content is: IX = $8000 and IY = $0004 when calling like (seg->seg = 4).
value = calseg(values, (BYTE)0, (BYTE)0, (UINT16)0x8000, seg->seg);

This exact same call works for CALLS, using the same calling convention. Is there something wrong?

By DarkSchneider

Paladin (965)

DarkSchneider's picture

28-12-2016, 11:49

Solved, the problem was that:

Quote:

IY = segment number to be called

BUT the segment byte value must be on higher part of IY, not the lower one. It is confusing.

Here the final code.

; BYTE calseg(TYPE arg1, TYPE arg2, TYPE arg3, UINT16 address, BYTE segment)
; pass always 5 parameters
calseg@:
	exx ; preserve parameters
	ld hl, 2
	add hl, sp ; hl = *address
	ld c, (hl)
	inc hl
	ld b, (hl)
	ld ix, 0
	add ix, bc
	inc hl ; hl = *segment
	ld b, (hl)
	ld c, 0
	ld iy, 0
	add iy, bc
	exx ; restore parameters
	jp _calseg
Page 1/2
| 2