Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

mos_flseek, fread, fwrite can't be used (easily) from Z80 mode #64

Open
davidgiven opened this issue May 28, 2023 · 11 comments
Open

mos_flseek, fread, fwrite can't be used (easily) from Z80 mode #64

davidgiven opened this issue May 28, 2023 · 11 comments
Labels
help wanted Extra attention is needed

Comments

@davidgiven
Copy link

davidgiven commented May 28, 2023

mos_flseek is defined to take a 32-bit file offset in E for the high 8 bits and HLU for the low 24 bits. Unfortunately, in Z80 mode we don't have access to HLU, meaning it's difficult to seek beyond 64kB without dropping into ADL mode.

mos_fread and fwrite have the same problem but it's worse there as you're passing pointers, and the stub doesn't do 16-bit fixup the way mos_load and mos_save do. So, using 16-bit pointers is hard.

@davidgiven davidgiven changed the title mos_flseek can't be used (easily) from Z80 mode mos_flseek, fread, fwrite can't be used (easily) from Z80 mode May 28, 2023
@breakintoprogram
Copy link
Owner

breakintoprogram commented May 29, 2023

You can access the full 24-bit registers in Z80 mode using LD.LIL HL, n, if that helps. The eZ80 is quite flexible with regards to shifting into 24-bit mode for single instructions. Please let me know if that's acceptable and I'll close this card.

Oh - the built-in BBC BASIC assembler doesn't support this syntax yet btw, but you can force it with a DEFB prefix.

@breakintoprogram breakintoprogram added the question Further information is requested label May 29, 2023
@breakintoprogram breakintoprogram moved this to In Progress in AGON Quark Firmware May 29, 2023
@davidgiven
Copy link
Author

Loading 24-bit registers isn't as easy as it looks. I had HL for the low bytes and A as the high byte; I went through way too many iterations of trying to get A into the top byte of HLU --- there aren't any instructions for doing it. What I eventually ended up with was poking three bytes into a ld.lil hl, Mmn instruction and then running it. Which is kinda evil. I see that BBC BASIC is doing a push.lil/modify/pop.lil, but that's evil too...

I don't see a generic backwards-compatible solution, as the same system call interface is used by both modes. As it is, because mos_load and mos_save extend 16-bit pointers from 16-bit mode they can't be used with 24-bit pointers. I think the only real solution would be something drastic like saying that if you make system calls with the top bit set of the system call number then all parameters are considered to be 16-bit, with internal extension to 24-bit with a zero or MB depending.

(There's another related issue in that when passing pointers, figuring out what to put into A is essentially impossible. It seems that the eZ80 has no legal ways of fetching MB from Z80 mode! The ld a, mb instruction is explicitly documented as being a nop in Z80 mode... I eventually had to hardcode a 4 here.)

@breakintoprogram
Copy link
Owner

Yes, there are instances where the eZ80 could be a bit more helpful. Appreciate the feedback. I'll have a think about this one.

@breakintoprogram breakintoprogram added enhancement New feature or request and removed question Further information is requested labels May 30, 2023
@breakintoprogram breakintoprogram moved this from In Progress to On Hold in AGON Quark Firmware May 30, 2023
@suborb
Copy link

suborb commented Jun 3, 2023

I just ran into this exact problem with fread/fwrite.

(There's another related issue in that when passing pointers, figuring out what to put into A is essentially impossible. It seems that the eZ80 has no legal ways of fetching MB from Z80 mode! The ld a, mb instruction is explicitly documented as being a nop in Z80 mode... I eventually had to hardcode a 4 here.)

I'm not sure how stable it is (in terms of ABI), but grabbing ld.lil a,(iy+8) on entry will yield mb which I'm fudging into pointers.

@radekh
Copy link

radekh commented Jul 16, 2023

I must be doing something wrong way. I'm experimenting with MOS command in Z80 mode. The program header looks:

00003B                   0069 ; MOS program header
00003B                   0070           ; there is space for code, data up to
00003B 00 00 00 00 00    0071           .align  $40
000040 4D 4F 53          0072           .db     "MOS"           ; MOS command magic number
000043 00                0073           .db     0               ; header version
000044 00                0074           .db     0               ; Z80 binary

And then somewhere in the program I do:

00010E                   0183           ; LD A,MD in Z80 mode should be NOP according
00010E                   0184           ; to Zilog documentation.  Lets see.
00010E 21 B1 01          0185           LD      HL,MSG_MB
000111 CD C4 01          0186           CALL    PRSTR
000114 3E 21             0187           LD      A,$21
000116 ED 6E             0188           LD      A,MB
000118 CD EF 01          0189           CALL    PRHEX8
00011B CD CB 01          0190           CALL    PRCRLF

When running, I got

MB: 0B

which is correct value.

@breakintoprogram breakintoprogram added help wanted Extra attention is needed and removed enhancement New feature or request labels Jul 16, 2023
@theflynn49
Copy link

@radekh : maybe CALL PRSTR or something before turns ADL to 1 and we are not in Z80 mode anymore ?

@radekh
Copy link

radekh commented Jul 18, 2023

@radekh : maybe CALL PRSTR or something before turns ADL to 1 and we are not in Z80 mode anymore ?

I'm new to eZ80. You can check if I'm doing anything suspicious. I recently pushed the code I use in this test into GitLab https://gitlab.com/Radek.Hnilica/agon-light-playground/-/blob/main/sysvars/sysvars.lst

You can also notice the LD A,MB is in the start code, which I rip from somewhere else. Sadly can't remember now from where.

@theflynn49
Copy link

@radekh
I spent some time to read the ez80 docs, and it appears to be far more complicated than I thought at first glance.

Anyway, it seems to me that Agon-Mos is running in MIXED mode (ADL=0 or 1, MADL=1) and the documentation doesn't really say what LD A,MB does in this MIXED mode. With ADL=0 and MADL=1 it should be NOP;NOP, but I would understand if the designers returned the MB flag when MADL=1, which means your program knows about paging.

Second thought, I read the beginning of your code, and the first thing you do is a conditional jump over the value of undefined A after a LD A,MB, which is supposed to be totally undefined. That is suspicious by definition. Next you mangle with the stack in ways I don't get yet, depending on the result of the random test I described above, which raises more questions.

But, I am as new as you regarding the ez80, so in fact I just don't know :D

@radekh
Copy link

radekh commented Jul 18, 2023

@theflynn49

Second thought, I read the beginning of your code, and the first thing you do is a conditional jump over the value of undefined A after a LD A,MB, which is supposed to be totally undefined. That is suspicious by definition. Next you mangle with the stack in ways I don't get yet, depending on the result of the random test I described above, which raises more questions.

But, I am as new as you regarding the ez80, so in fact I just don't know :D

That code I exactly ripe from somewhere. Some INC files. When I was making template for MOS command in Z80 mode, it did not want to work. So I found some example, however I had to go through INI files manually implementing preprocessor and picking up only code for ADL=0. It is magic for me, howe ver, it works. So I put the task to get understanding of it aside in favour to make some working program I can use for learning.

It goes slowly. The whole instruction prefix switching of modes is still Greek for me. Whenever I think I understand it, next instruction blow in my face.

@theflynn49
Copy link

theflynn49 commented Jul 19, 2023

@radekh
Poking around, I just discovered this :

The "official" 16-bits app template (aka z80 mode) for Agon-MOS is here :
https://github.com/breakintoprogram/agon-projects/blob/main/ASM/Hello%20World%2016/init.asm

You can see that he uses a LD A,MB instruction line 73, while being in mixed mode.
That is not a definitive proof, but it strongly suggests that MIXED mode let LD A,MB work as in ADL mode.

Hope this is convincing enough to you, as it is to me.

@Ed8562
Copy link

Ed8562 commented Sep 9, 2023

mos_fread and fwrite have the same problem but it's worse there as you're passing pointers, and the stub doesn't do 16-bit fixup the way mos_load and mos_save do. So, using 16-bit pointers is hard.

Perhaps it would have been easier if the API accepted a pointer to a parameter block rather than parameters directly in registers. This could be implemented as an alternative to using RST 08h. The parameter block would contain the registers values - A (MOS fn#), BCU, DEU, HLU, IXU, IYU, Flags - filled as necessary by the application and executed via, say, RST20h with HLA regs pointing to the parameter block. Any values returned by MOS would be via the parameter block.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
Status: On Hold
Development

No branches or pull requests

6 participants