MSX1 File I/O from binary launched from Basic

Post Reply
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

MSX1 File I/O from binary launched from Basic

Post by Jens »

Please forgive me, my MSX knowledge has deteriorated a bit over the past 30 years...

Short version: What file I/O is available from the BIOS/BASIC ROMs, and is that available in the C-library or do I have to call into the BIOS myself?

Long version:
I want to write a game that can be launched with BLOAD "GAME.MSX",R , that loads further level files from a floppy. A binary block read is enough, I don't need to seek or read individual bytes, and I don't need subdirectories.

As a quick test I wrote:

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

char buf[256];

void main() {
	FILE *f;
	printf("Hello world!\n");
	f = fopen("a:level.bin", "rb");
	memset(buf, 0, sizeof(buf));
	fread(buf, 1, 256, f);
	fclose(f);
	printf("result: %s %p\n", buf, f);
}
I successfully built that into a binary file that can be loaded in blueMSX. It prints "Hello World!" as expected, but gets a 0 file handle.
level.bin exists and shows in a directory listing.

Obviously the BASIC runtime has access to the disc functions, and digging through the documentation parts of the MSX-DOS runtime are supposed to be part of the BIOS. Though I'm not clear which functions are part of the BIOS, and what functions are part of the kernel that is read from an MSX-DOS boot disc.

So the questions are:
- which disc functions are part of the (Disc-)BIOS of an MSX1 machine, without booting into MSX-DOS?
- do they have a fopen API wrapper, or do I have to go through BIOS calls? (Which would be fine, I just don't know...)
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

I don’t think there’s any support at the moment.

I’ve just read some docs and it looks like the bdos calls are available via 0F37Dh from BASIC and I know we added a possible redirection for call 5. So if that’s right, give me a few days and I’ll have something working.
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

Thank you, yes, BDOS sounds like what I was looking for: https://github.com/apoloval/msx-system/ ... k/bdos.txt
(Why was that so hard to find? Sigh.)
This was more of a "What am I doing wrong?" style question, please don't feel pressured to fix this for me.
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

Quick test:

Code: Select all

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <arch/z80.h>
#include <arch/msx/asm.h>

char buf[256];

typedef struct _FCB {
	char dr;
	char fname[8];
	char fext[3];
	char ex;
	char s1;
	char s2;
	char rc;
	long filesiz;
	short date;
	short time;
	char devid;
	char dirloc;
	short strcls;
	short clrcls;
	short clsofs;
	char cr;
	long rn;
} FCB;

FCB fcb;

void main() {
	FILE *f;
	printf("Hello world!\n");

	memset(&fcb, 0, sizeof(FCB));
	fcb.dr = 1;
	strcpy(fcb.fname, "LEVEL");
	strcpy(fcb.fext, "BIN");

	Z80_registers regs;
	memset(&regs, 0, sizeof(Z80_registers));
	regs.Bytes.C = 0x0F;
	regs.Words.DE = &fcb;
	AsmCall(0xF37D, &regs, REGS_MAIN, REGS_AF);
	printf("bdos: %u %lu\n", regs.Bytes.A, fcb.filesiz);
}
Am I using AsmCall wrong, or are there constraints on the location of the fcb?
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

I think the FCB can’t be in segment 1 when calling from basic however since the org defaults to 40000 that probably isn’t the issue.
stefano
Well known member
Posts: 2218
Joined: Mon Jul 16, 2007 7:39 pm

Re: MSX1 File I/O from binary launched from Basic

Post by stefano »

There's a possibility you can try to explore if you think to use tape...
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

stefano wrote: Sun Jul 07, 2024 8:54 pm There's a possibility you can try to explore if you think to use tape...
You know, as Abraham Lincoln said "Everything is a tape game if you're brave enough." It may be a bit uncomfortable going between levels, though.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

As a status update, I've got programs linking, if testing goes well this evening it should be available in the next nightly.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

I've run some tests on an emulated MSX2 and it seems to work. So full stdio/fcntl access for BLOAD programs will be available in the nightly tomorrow morning - feedback gratefully received.

As a quick guide:

Code: Select all

* Create a disc image with a bload binary with file io implemented using the MSXDOS1 BDOS api:

zcc +msx -subtype=diskio --msxdos1 [files] -create-app

* Create a disc image with a bload binary with file io implemented using the MSXDOS2 BDOS api:

zcc +msx -subtype=diskio --msxdos2 [files] -create-app

* Create a disc image with a bload binary with access to V9938 modes and file io implemented using the MSXDOS2 BDOS api:

zcc +msx -subtype=diskio --msxdos2 [files] -create-app -lmsx2

* Create a bload binary with file io implemented using the MSXDOS1 BDOS api:

zcc +msx -subtype=binio --msxdos1 [files] -create-app

* Create a bload binary with file io implemented using the MSXDOS2 BDOS api:

zcc +msx -subtype=binio --msxdos2 [files] -create-app
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

Thank you, seems to work fine!
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

That's great, thanks for the feedback.

If you're using MSXDOS1 you might find that the binary size has increased too much - this will be due to the sector cache used to speed up IO. You can reduce the number of FCBs + caches using the pragma detailed on the CP/M page here: https://github.com/z88dk/z88dk/wiki/Pla ... ile-access.

Using MSXDOS2 is a lot less memory heavy.
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

So, to free up more memory I banked out the BASIC ROM and load directly to 0x4000.
Looking at the memory in the debugger it seems to have loaded only the first 128byte.
Changing the address to after the binary it loads the whole file.
Any ideas what I can look for? Is there special case handling in fread that assumes an address after 0x8000, or am I overwriting anything the library needs?
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

It’s the same routines used for CPM so there’s no address preference. However if you’re messing around with banking it might be the first record is read into RAM but dos ends up being paged in so subsequent records fail.

As mentioned above I read docs that indicated the FCB can’t be in the 0x4000 - maybe that’s also the case for other pointers.

Text files read into a cache so they should work.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

dom wrote: Sat Jul 13, 2024 2:47 pm It’s the same routines used for CPM so there’s no address preference. However if you’re messing around with banking it might be the first record is read into RAM but dos ends up being paged in so subsequent records fail.
What is actually happening is this:

Code: Select all

        while ( len ) {
            unsigned long record_nr = fc->rwptr/SECSIZE;
            offset = fc->rwptr%SECSIZE;
            if ( ( size = SECSIZE - offset ) > len ) {
                size = len;
            }
            _putoffset(fc->ranrec,record_nr);
            if ( size == SECSIZE ) {
                bdos(CPM_SDMA,buf);
                if ( bdos(CPM_RRAN,fc) ) {
                    swapuid(uid);
                    return cnt-len;
                }
            } else {
                if ( cpm_cache_get(fc, record_nr, 1) ) {
                    swapuid(uid);
                    return cnt-len;
                }
                memcpy(buf,fc->buffer+offset,size);
            }
            buf += size;
            fc->rwptr += size;
            len -= size;
        }
 
So I'm guessing the low byte of the file size is 0x80 in your case, that's being read by the cpm_cache_get path. The rest of the file is being read by the CPM_RRAN. I think we could probably use a pragma to always go via the cache_get route and avoid this problem. It'll be slower, but at least the data would be loaded. Write always goes via the cache.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

I've added that option now (-pragma-define:CPM_READ_CACHE_ALWAYS=1), it's enabled by default for BLOAD environments - hopefully that will get the file loaded correctly.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

dom wrote: Sat Jul 13, 2024 2:47 pmAs mentioned above I read docs that indicated the FCB can’t be in the 0x4000 - maybe that’s also the case for other pointers.
As a note for future me:
There are some limitations when calling the system via 0F37Dh, particularly to do with error handling and abort routines. Also no parameters may be passed in page-1, unless they are in the master disk ROM (as they will be for disk BASIC) since the master disk ROM will be paged into page-1 when such a function call is made. The individual function descriptions mention the differences for particular functions.
From: http://map.grauw.nl/resources/dos2_functioncalls.php
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

Good find. The question is, is this better handled on the application side by throwing an error and asking the application to be designed around this, or working around it with an intermediate buffer in another page?
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

Jens wrote: Sat Jul 13, 2024 8:54 pm Good find. The question is, is this better handled on the application side by throwing an error and asking the application to be designed around this, or working around it with an intermediate buffer in another page?
As above, I've updated the BLOAD environment to use an intermediate buffer - it's a sensible default for that environment and will follows our "just works" mantra.
Jens
Member
Posts: 21
Joined: Sun Jul 07, 2024 11:02 am

Re: MSX1 File I/O from binary launched from Basic

Post by Jens »

I updated to the nightly and it works! While "just works" is nice, it is extra work for you and as you want to support many platforms it may make maintenance harder.

BTW, I used this page to disable the BASIC ROM:
https://map.grauw.nl/sources/raminpage1.php

The first function on that page didn't seem to select RAM correctly, the second one worked fine.

Here it is translated into a C function:

Code: Select all

#define EXPTBL 0xFCC1
#define ENASLT 0x24

// https://map.grauw.nl/sources/raminpage1.php
void EnableRAM()
{
	#asm
				ld     	a,(EXPTBL+3)
				ld     	b,a				; check if slot is expanded
				and    	a
				jp     	z,Ena_RAM2_jp
				ld     	a,(0xFFFF)		; if so, read subslot value first
				cpl        				; complement value
				and    	0b11000000
				rrca					; shift subslot bits to bits 2-3
				rrca
				rrca
				rrca
				or     	b
				ld     	b,a
Ena_RAM2_jp: 	in     	a,(0xA8)			; read slot value
				and    	0b11000000		; shift slot bits to bits 0-1
				rlca
				rlca
				or     	b
				ld     	h,0x40			; select slot
				call  	ENASLT
				ret 
	#endasm
}
I think for now I'm good with memory, the next step would be to use the memory under the BIOS ROM, but then I'll have to add a wrapper for system calls and IRQ.
User avatar
dom
Well known member
Posts: 2194
Joined: Sun Jul 15, 2007 10:01 pm

Re: MSX1 File I/O from binary launched from Basic

Post by dom »

Jens wrote: Sun Jul 14, 2024 9:00 am I updated to the nightly and it works! While "just works" is nice, it is extra work for you and as you want to support many platforms it may make maintenance harder.
This one is no bother at all, it's just a tiny tweak to the flow control: https://github.com/z88dk/z88dk/commit/4 ... 2dd348b591
BTW, I used this page to disable the BASIC ROM:
https://map.grauw.nl/sources/raminpage1.php
That's great, thank you - I think I can use that to setup a heap in that area.
Post Reply