Safe set BIOS and restore RAM on page 0 from MSX-DOS?

Page 1/4
| 2 | 3 | 4

By DarkSchneider

Paladin (819)

DarkSchneider's picture

11-10-2016, 09:08

Is this safe?

; set BIOS
LD H, 0 ; page 0
; ROMSLT = Main BIOS slot ID. (MSX2 and up only)
LD A, ROMSLT
LD IY, (ROMSLT-1)
LD IX, ENASLT
CALL CALSLT ; MSX-DOS environment so inter-slot call

; code using the BIOS directly
...
; code end

; restore RAM
LD H, 0 ; page 0
; RAMAD0 = Slot address of RAM in page 0 (DOS)
LD A, RAMAD0
CALL ENASLT ; we are in BIOS environment so direct call

ENASLT use SlotId format, so it is supposed ROMSLT contains the correct data. Is the same for RAMAD0?.

Login or register to post comments

By DarkSchneider

Paladin (819)

DarkSchneider's picture

11-10-2016, 13:55

Correction: the LD A, SOMETHING should be LD A, (SOMETHING). We want the SlotId value not the address.

By zeilemaker54

Master (243)

zeilemaker54's picture

11-10-2016, 17:16

That is unsafe code. Depending on the slot configuration, CALSLT may alter the SSR after the ENASLT routine is called. That could destroy the slot configuration you wanted in the first place by calling ENASLT.
I remember a solution on the MSX datapack disks (mis)using the NMI jumpentry and hook for this purpose...

By DarkSchneider

Paladin (819)

DarkSchneider's picture

11-10-2016, 18:46

I only have seen NMI usage for SUBROM calling from MSXDOS. It is supposed that passing the SlotId should set the subslots according. So, if RAMAD0 (the original state from MSXDOS before setting the BIOS in page 0) has the full SlotId info (like ROMSLT) the ENASLT should set it. But not sure if it has the full SlotId info.

By hit9918

Prophet (2858)

hit9918's picture

12-10-2016, 00:26

but enaslt page 0 doesnt work. and if things would work, then as CALSLT returns it does cleanup and undo what ENASLT did.

how about a software interrupt to an fd9a interrupt handler.
DOS must route interrupts to bios and then fd9a faces the bios flipped in.

		DI		;make DI like z80 when it acts upon interrupt
		ld a,128
		ld (softint),a  ;set it like a VDP status flag
		RST 0x38	;trigger software interrupt :)
		...
		
		
fd9a code:	ld a,(softint)
		and 128
		ret z
		ld a,0
		ld (softint),a	;reset software device request :) because other devices too make 0x38
		EI

		;now you can call the bios
		
		ret		;RAMAD slot situation gets restored
		
softint		db 0

maybe the 0x38 route has some more speed than CALSLT because it goes without slotID processing.

a version with a function vector.
have many functions without being into handler coding all day.

intfunc		dw 0

		DI
		ld hl,myfunction
		ld (intfunc),hl
		rst 0x38
		DI
		ld hl,anotherfunc
		ld (intfunc),hl
		rst 0x38
		...
		
		
fd9a code:	hl,(intfunc)
		ld a,h
		or l
		ret z
		ld de,0
		ld (intfunc),0	;clear "device status"
		EI
		jp (hl)		;the RET of the jumped function is like ret from handler
		
		
myfunc:		;use bios
		ret
		
anotherfunc:	;use bios
		ret

By hit9918

Prophet (2858)

hit9918's picture

12-10-2016, 00:32

p.s. the fd9a handler and myfunc anotherfunc must be located above 0x3fff.

By hit9918

Prophet (2858)

hit9918's picture

12-10-2016, 00:46

and the fd9a handler should be above bfff.
when an interrupt happens while some disk ROM is flipped in, who knows.
the only RAM page that is always there is page 3.

By DarkSchneider

Paladin (819)

DarkSchneider's picture

12-10-2016, 09:28

MSXDOS saves some BIOS in the low memory addresses, before the TPA, maybe ENASLT is one of them and can be used without CALSLT. I think I'll try some things. The interrupt, even if working, is not the best scenario because the idea is to set it within the main loop to queue all the BIOS operations and then dispatch all in a row, the interrupt is used for other things and could generate rare behavior.

By DarkSchneider

Paladin (819)

DarkSchneider's picture

12-10-2016, 11:46

OK, it was a problem of calling ENASLT for restoring the RAM, because while is being executed we change the slot 0 so it can't continue. The direct ENASLT works, it seems to be saved by MSXDOS.
So the process is use ENASLT to set BIOS. Then restore RAM getting the value from RAMAD0 (it has the SlotID value for RAM page 0) and using port #A8 (really not like this) to restore the primary slot, and then restore the secondary slot using FFFF. Restoring the secondary is not necessary if the BIOS slot is not expanded and/or are in different slots (BIOS and RAM), but is safer to do it.

If someone interested, here is the code used:

.z80

; define
ENASLT equ 024h
CHGCAP equ 0132h
RAMAD0 equ 0f341h
ROMSLT equ 0fff7h
BEEP equ 0c0h

; out of page 0, better use the linker, but for test OK
;org 04000h
runbio@:
	; set BIOS
	LD H, 0 ; page 0
	; ROMSLT = Main BIOS slot ID. (MSX2 and up only)
	LD A, (ROMSLT)
	CALL ENASLT

	; BIOS working
	ld a, (CAPL)
	call CHGCAP
	ld a, (CAPL)
	xor 1 ; invert
	ld (CAPL), a
	call BEEP
	
	; restore RAM
	; manually
	ld a, (RAMAD0) ; SlotID for RAM page 0
	ld c, a ; save on c
	; set primary slot
	and 003h ; remove all but primary slot
	ld b, a
	in a, (0a8h)
	and 0fch ; clean page 0
	or b ; set primary slot for page 0
	out (0a8h), a
	; secondary slot
	ld a, c ; restore RAMAD0 and check if expanded
	rlca
	ret nc ; if not expanded, return
	rrca ; restore
	and 07fh ; clean the expanded bit
	ld b, a ; set the subslot on b
	srl b
	srl b
	ld a, (0ffffh) ; get SSSR
	cpl ; invert
	and 0fch ; clean page 0
	or b ; put the RAMAD0 sub-slot
	ld (0ffffh), a ; write SSSR
	ret

; vars
CAPL: db 0

; export
public runbio@

END


And here the C code for testing:

#define NEWKEY(index) (*(unsigned*)(0xFBE5+index))
#define JIFFY (*(unsigned*)0xFC9E)
#define RAMAD0 (*(char*)0xF341)
#define ROMSLT (*(char*)0xFFF7)
#define EXBRSA (*(char*)0xFAF8)
#define SLTTBL (char*)0xFCC5

#include < stdio.h >

VOID runbio();

VOID main(argc, argv)
int argc;
char *argv[];
{
	static BOOL run;
	static unsigned jiffy;
	/*char ramad0 = RAMAD0;
	char romslt = ROMSLT;
	char exbrsa = EXBRSA;
	char ffff = (*(char*)0xFFFF);
	char slttbl = *SLTTBL;

	printf("ROMSLT: %u\n", (unsigned)romslt);
	printf("EXBRSA: %u\n", (unsigned)exbrsa);
	printf("RAMAD0: %u\n", (unsigned)ramad0);
	printf("FFFF: %u\n", (unsigned)ffff);
	printf("SLTTBL0: %u\n", (unsigned)slttbl);
	slttbl = *(SLTTBL+1);
	printf("SLTTBL1: %u\n", (unsigned)slttbl);
	slttbl = *(SLTTBL+2);
	printf("SLTTBL2: %u\n", (unsigned)slttbl);
	slttbl = *(SLTTBL+3);
	printf("SLTTBL3: %u\n", (unsigned)slttbl);
	return;*/
	
	run = TRUE;
	while(run) {
		jiffy = JIFFY;
		printf("Loop start. Running BIOS:\n");
		runbio();
		printf("Loop end\n");
		if(NEWKEY(8) != 0xffff) {
			run = FALSE;
		}
		while(jiffy == JIFFY) ;
	}
}


The linker line, if not using the org 4000h, is like this:
L80 A:\LIB\CK,biostest,/P:4000,biosasm,A:\LIB\MLIB/S,A:\LIB\CLIB/S,A:\LIB\CRUN/S,A:\LIB\CEND,biostest/N/Y/E:xmain

Testing on different machines could help.

By DarkSchneider

Paladin (819)

DarkSchneider's picture

12-10-2016, 14:00

But is rare, if works from RAM to BIOS, why not from BIOS to RAM? It should fail too the first call to ENASLT.

By hit9918

Prophet (2858)

hit9918's picture

12-10-2016, 21:39

so, bios ENASLT CALSLT in page 0 dont work and now you write your own slot code... it is a long story.
first do DI.
and there is not one FFFF, but there are four FFFF. one per primary slot.
and then 1 of the 4 entries of SLTTBL need update.

the software interrupt. you said "queue", like one got to wait for some hardware to make interrupt.
no, just CALL 0x38.
and 0x38 means: "flip slot to bios, call fd9a, then flip slot back to RAMAD0".
Doesnt this sound interesting Big smile

Page 1/4
| 2 | 3 | 4