Jump to content
IGNORED

CPM/Z-80 card for the 1090XL -- Calling anyone with Z-80 experience!


Recommended Posts

1 hour ago, joeventura said:

WIth the announcement of the Z80 being discontinued, its time to buy up a bunch for this it seems

I am pretty sure it's just the DIP package being discontinued.  There are other form factors / options available.

Link to comment
Share on other sites

1 hour ago, joeventura said:

WIth the announcement of the Z80 being discontinued, its time to buy up a bunch for this it seems

There will be lots of NOS available for quite sometime, since this was a very popular CPU. And probably won't have to worry about fake chips for awhile, until the stock eventually runs low.

 

For instance UTsource has 10,000 in stock of this brand.

image.thumb.png.97969fdcd1a61c44da19c728698b70ec.png

Quote

The LH0080B is a Z80B-CPU (DIP-40) manufactured by Sharp. It is a CMOS version of the Z80 8-bit microprocessor. It is an improved version of the Z80A, offering improved performance and power consumption. Features of the LH0080B include: 8-bit architecture Clock speeds of up to 10 MHz 16-bit address bus 8-bit data bus On-chip memory management On-chip interrupt controller On-chip timer On-chip DMA controller On-chip I/O ports.

Buy LINK

  • Like 3
  • Thanks 1
Link to comment
Share on other sites

Posted (edited)

I hate hoarders.

 

Last week I wanted a single 8MHz Z80 to complete a Zeta 2 SBC. Digikey, Element14, Jameco, Mouser, all are out of stock of anything above 6MHz. My best option was some dude in Germany through eBay who at least had what looked like some original ST packaging in his listings - I suspect everything eBay is fake now, even got some 4164 RAM recently that was sanded down and relabeled.

 

(have never used UTsource, that may change)

 

If I understand this project correctly it is designed to connect to the expansion port on the 800XL series of computers. The Incognito card in the 800 apparently has this too - have you tried connecting to an Incognito-equipped 800?

Edited by aeberbach
Link to comment
Share on other sites

1 hour ago, aeberbach said:

I hate hoarders.

 

Last week I wanted a single 8MHz Z80 to complete a Zeta 2 SBC. Digikey, Element14, Jameco, Mouser, all are out of stock of anything above 6MHz. My best option was some dude in Germany through eBay who at least had what looked like some original ST packaging in his listings - I suspect everything eBay is fake now, even got some 4164 RAM recently that was sanded down and relabeled.

 

(have never used UTsource, that may change)

 

If I understand this project correctly it is designed to connect to the expansion port on the 800XL series of computers. The Incognito card in the 800 apparently has this too - have you tried connecting to an Incognito-equipped 800?

The CP/M card is designed to plug into a slot on a 1090XL Expansion System board that is connected to a 600XL or 800XL PBI port.  With an adapter, it can work on a 130XE.  If even possible, an Incognito-equipped 800 would be awkward, at best.

 

The Z-80 production was stopped with little warning.  It would have been nice to know a year or two in advance.

Link to comment
Share on other sites

Z80 production has not stopped yet. According to the Z80 EOL announcement https://www.mouser.com/PCN/Littelfuse_PCN_Z84C00.pdf they are accepting last time buy’s until June 14, 2024. If you want 1,000,000 chips - put your order in soon. Zilog might ask you to sign a NCNR contract and pay in advance - you may be able to negotiate a terms, delivery schedule, etc.

Link to comment
Share on other sites

8 minutes ago, Forrest said:

Z80 production has not stopped yet. According to the Z80 EOL announcement https://www.mouser.com/PCN/Littelfuse_PCN_Z84C00.pdf they are accepting last time buy’s until June 14, 2024. If you want 1,000,000 chips - put your order in soon. Zilog might ask you to sign a NCNR contract and pay in advance - you may be able to negotiate a terms, delivery schedule, etc.

Well, I don't see anyone lining up to order 1,000,000 Z-80 chips. 

 

My biggest gripe is that the 1090XL Z-80 CP/M card was never attempted until recently.  Then, on the very day I get a command prompt up I find out that the Z-80 is discontinued.  Had I known six months ago, I wouldn't have bothered.    😞

 

Please don't mention substituting the ez80 until after you review the data sheets.

Link to comment
Share on other sites

11 hours ago, venom4728a said:

I just ordered 6 Z84C0010PEG chips. Hoping I can order a Z80 card for the 1090xl

Since the card is finished and working, I'll have to put an interest thread out there.  (Any of these cards will be shipped with signature required for delivery.)

 

One caveat is that the basics have been completed for CP/M to work.  Quite frankly, somebody could spend weeks or even months fine tuning the code and adding features.  I am not going to spend that time and there will literally have to be some people willing to make improvements.  I've released the source code so it should be a lot easier for somebody to pick this up.

 

On another note, I am having major problems with the format.com utility working.  It's something stupidly simple....or possibly a compiler problem.  I am not sure and suspecting a compiler issue.  It's almost as though the printb function is never exiting correctly for some strange reason.  (At least that's the current working theory.)  I really don't want to spend much more time on this.

 

Here's the current state of the format.com utility:

(Please disregard all of the commented out junk code as it's been used to test what works and what isn't working.)

format.c

 

 

 

 

  • Like 2
Link to comment
Share on other sites

Posted (edited)
2 hours ago, reifsnyderb said:

Here's the current state of the format.com utility:

Here's some feedback in case you still want to finish it :)

 

#define IOSTRUCTUREADDR 0xFF80
#define SVTMAXDISKADDR 0xFFA0

unsigned char *io = (unsigned char *)IOSTRUCTUREADDR;
unsigned char *io_disk = (unsigned char *)IOSTRUCTUREADDR+0x03;
unsigned char *io_track = (unsigned char *)IOSTRUCTUREADDR+0x04;
unsigned char *io_sector = (unsigned char *)IOSTRUCTUREADDR+0x06;
unsigned char *io_dma = (unsigned char *)IOSTRUCTUREADDR+0x08;

This could be a struct.

 

void printb_asm(unsigned char byte)
{
#asm
    ld hl,2
    add hl,sp               ; skip over return address on stack
    ld c,(hl)               ; c = byte
    call CONOUT
#endasm
}

Even though z88dk does not have the elaborate API that the ACK has, you do not need inline assembler. There's bios(int func,int arg,int arg2). Conout would be bios(BIOS_CONOUT, byte, 0).

 

unsigned int printb(const char * StrOutput)
{
        //unsigned char CharOutput[1];

        // Print the string
        unsigned int i = 0;
        while(i < 80)
                //if(StrOutput[i] == "\n")
                {
        printb_asm(StrOutput[i]);

        if(StrOutput[i]=="\n")
                {
                        i=100;
                }
                i++;
        };

        return(0);
}

while (i<80) { /* ... */ i++; } can be written as for (i=0; i<80; i++) { /* ... */ }

The same for all your other while loops.

 

You compare a character (StrOutput[i]) to a pointer ("\n"). It is '\n' you want.

 

To break out of a loop in C, you can use break; like: if (StrOutput[i] == '\n') break; No need to set i to 100.

 

return is not a function. The parenthesis are not needed.

 

CP/M BDOS has a writestring/printstring routine (function 9). It expects the string to end with '$'. z88dk has bdos(int func, int arg) to call bdos functions directly.

 

unsigned int writeb(unsigned char drive[1], unsigned char track[2], unsigned char sector[2], unsigned char * write_sector_buffer)
{
        unsigned int i;

        io_disk[0]=drive[0];

        io_track[0]=track[0];
        io_track[1]=track[1];

        io_sector[0]=sector[0];
        io_sector[1]=sector[1];

        io_dma = &write_sector_buffer[0];

#asm
        call WRITE
#endasm

        return(0);
}

&write_sector_buffer[0] is equal to just write_sector_buffer. It is already a pointer. Now you are taking the address of the first element, which is the same.

 

int main(int argc, char *argv[])
{
        unsigned char bPreviousDrive[1];
        unsigned char sector_buffer[128];
/*....*/
        writeb(argv[1][0],0,0,sector_buffer[0]);
/*...*/

Here you put sector_buffer[] on the stack. It's faster to make it a global variable. Also, no need to make bPreviousDrive an array of 1.

 

The arguments writeb() expects are all pointers, but you pass a character, a null pointer, another null pointer, and a character. Then writeb() dereferences a null pointer. On a modern OS that would be a segmentation fault ;)

 

It's easier to define writeb() as writeb(unsigned char drive, unsigned int track, unsigned int sector, unsigned char *sector_buffer) and assign the values with track & 0xff for the low byte, and track >> 8 for the high byte.

 

If you turn io to a pointer to a proper structure, it's even as simple as io->track = track.

 

Hope this helps :)

Edited by ivop
  • Like 2
  • Thanks 1
Link to comment
Share on other sites

20 minutes ago, ivop said:

Here's some feedback in case you still want to finish it :)

Thanks!  I'd like to see the format.com work.

 

20 minutes ago, ivop said:
#define IOSTRUCTUREADDR 0xFF80
#define SVTMAXDISKADDR 0xFFA0

unsigned char *io = (unsigned char *)IOSTRUCTUREADDR;
unsigned char *io_disk = (unsigned char *)IOSTRUCTUREADDR+0x03;
unsigned char *io_track = (unsigned char *)IOSTRUCTUREADDR+0x04;
unsigned char *io_sector = (unsigned char *)IOSTRUCTUREADDR+0x06;
unsigned char *io_dma = (unsigned char *)IOSTRUCTUREADDR+0x08;

This could be a struct.

I originally planned to make this a structure but was unsure about how to directly address a memory location.  So, I made distinct pointers as I planned on having problems.  (It took a little research to find out how to directly address a memory location as it's rarely done anymore.)

 

My thought is the structure would look something like this:

 

struct io_structure{

  unsigned char complete[0];

  unsigned char status[0];

  unsigned char command[0];

  unsigned char disk[0];

  unsigned character track[2];

  unsigned character sector[2];

  unsigned character dma[2];

};

 

Then later defined as...

 

struct io_structure *io = (unsigned char *)IOSTRUCTUREADDR;

 

 

 

 

20 minutes ago, ivop said:
void printb_asm(unsigned char byte)
{
#asm
    ld hl,2
    add hl,sp               ; skip over return address on stack
    ld c,(hl)               ; c = byte
    call CONOUT
#endasm
}

Even though z88dk does not have the elaborate API that the ACK has, you do not need inline assembler. There's bios(int func,int arg,int arg2). Conout would be bios(BIOS_CONOUT, byte, 0).

I did this so as to try and save space.  Presently, the program is already over 5k and all it does is parse the command line then send a couple commands to the Atari.  (I temporarily, and for debugging purposes, added stdio.h so as to use printf() and the code ballooned to over 7k.)

 

20 minutes ago, ivop said:
unsigned int printb(const char * StrOutput)
{
        //unsigned char CharOutput[1];

        // Print the string
        unsigned int i = 0;
        while(i < 80)
                //if(StrOutput[i] == "\n")
                {
        printb_asm(StrOutput[i]);

        if(StrOutput[i]=="\n")
                {
                        i=100;
                }
                i++;
        };

        return(0);
}

while (i<80) { /* ... */ i++; } can be written as for (i=0; i<80; i++) { /* ... */ }

The same for all your other while loops.

Is there any advantage to using a for loop as opposed to a while loop?

 

20 minutes ago, ivop said:

You compare a character (StrOutput[i]) to a pointer ("\n"). It is '\n' you want.

Umm, yeah....about that.  I completely missed it and it was a major, major headache.  The guy on the z88dk forum caught it.

 

 

20 minutes ago, ivop said:

To break out of a loop in C, you can use break; like: if (StrOutput[i] == '\n') break; No need to set i to 100.

I was wondering if break wasn't working and trying other ways to get out of the loop.

20 minutes ago, ivop said:

return is not a function. The parenthesis are not needed.

Force of habit and keeping to a "standard" or sorts.  Maybe a bad idea?

 

 

Note:  I added some responses with a pile of asterisks before them, below.....

20 minutes ago, ivop said:

CP/M BDOS has a writestring/printstring routine (function 9). It expects the string to end with '$'. z88dk has bdos(int func, int arg) to call bdos functions directly.

 

 

*********  I wasn't aware of that one.  Now that printing is working, I don't see the advantage of changing it.  But, I can be convinced.....

 

 

 

*********  Now we are getting into stuff that's still mostly pseudo code.   🙂 

 

 

unsigned int writeb(unsigned char drive[1], unsigned char track[2], unsigned char sector[2], unsigned char * write_sector_buffer)
{
        unsigned int i;

        io_disk[0]=drive[0];

        io_track[0]=track[0];
        io_track[1]=track[1];

        io_sector[0]=sector[0];
        io_sector[1]=sector[1];

        io_dma = &write_sector_buffer[0];

#asm
        call WRITE
#endasm

        return(0);
}

&write_sector_buffer[0] is equal to just write_sector_buffer. It is already a pointer. Now you are taking the address of the first element, which is the same.

 

********** Dealing with pointers has always been a weak point.   🙂   

 

 

********* Looking at what's being done, maybe writeb() should be removed and made inline code as it's kind of redundant anyhow.

 

 

 

int main(int argc, char *argv[])
{
        unsigned char bPreviousDrive[1];
        unsigned char sector_buffer[128];
/*....*/
        writeb(argv[1][0],0,0,sector_buffer[0]);
/*...*/

Here you put sector_buffer[] on the stack. It's faster to make it a global variable. Also, no need to make bPreviousDrive an array of 1.

Good point.

 

20 minutes ago, ivop said:

The arguments writeb() expects are all pointers, but you pass a character, a null pointer, another null pointer, and a character. Then writeb() dereferences a null pointer. On a modern OS that would be a segmentation fault ;)

 

It's easier to define writeb() as writeb(unsigned char drive, unsigned int track, unsigned int sector, unsigned char *sector_buffer) and assign the values with track & 0xff for the low byte, and track >> 8 for the high byte.

 

If you turn io to a pointer to a proper structure, it's even as simple as io->track = track.

 

Hope this helps :)

 

Thanks!

 

 

 

Link to comment
Share on other sites

Posted (edited)
1 hour ago, reifsnyderb said:

Thanks!  I'd like to see the format.com work.

 

I originally planned to make this a structure but was unsure about how to directly address a memory location.  So, I made distinct pointers as I planned on having problems.  (It took a little research to find out how to directly address a memory location as it's rarely done anymore.)

 

My thought is the structure would look something like this:

 

struct io_structure{

  unsigned char complete[0];

  unsigned char status[0];

  unsigned char command[0];

  unsigned char disk[0];

  unsigned character track[2];

  unsigned character sector[2];

  unsigned character dma[2];

};

Here complete[0] is a zero-length array. Compiler should complain. See end of post.

z88dk has sizeof(int)==2, so this should work:

 

struct io_structure{
  unsigned char complete;
  unsigned char status;
  unsigned char command;
  unsigned char disk;
  unsigned int track;
  unsigned int sector;
  unsigned int dma;
};

 

1 hour ago, reifsnyderb said:

Then later defined as...

 

struct io_structure *io = (unsigned char *)IOSTRUCTUREADDR;

 

struct io_structute *io = (struct io_structure *)IOSTRUCTUREADDR;

 

1 hour ago, reifsnyderb said:

I did this so as to try and save space.  Presently, the program is already over 5k and all it does is parse the command line then send a couple commands to the Atari.  (I temporarily, and for debugging purposes, added stdio.h so as to use printf() and the code ballooned to over 7k.)

Wow, that's pretty big, considering that dos2dir with the ACK is only ±1700 bytes.

 

1 hour ago, reifsnyderb said:

Is there any advantage to using a for loop as opposed to a while loop?

In the end it works the same, but IMHO it improves readability, and is less lines of code.

1 hour ago, reifsnyderb said:

Force of habit and keeping to a "standard" or sorts.  Maybe a bad idea?

Visually it looks like you are calling a function (func(args)), but it's a reserved word in C and means return from function. It does not call anything. The parenthesis are now part of the expression that evaluates to the return value, and hence are superfluous.  It's not necessarily bad, but visually it does not convey the right meaning.

 

Quote

*********  I wasn't aware of that one.  Now that printing is working, I don't see the advantage of changing it.  But, I can be convinced.....

Code size. A single call to bdos will be less code than your loop and calling conout.

 

I just installed z88dk and I must say I am pretty underwhelmed. It silently accepts wrong code and does not even issue a warning, like when calling functions with wrong arguments. gcc would say expected ‘unsigned char *’ but argument is of type ‘unsigned int’ , and the ACK says: (strict) illegal conversion of int to pointer, or when comparing chars to pointers (== on int and pointer), zero-length arrays ((strict) array size is 0), etc... It's difficult coding in a language you are not fluent in and the compiler does not tell you when you do things wrong.

 

Another thing, I think your executable is also large because it contains all the code to parse the command line and populate **argv. You can probably get a smaller binary if you get the first command line argument directly from the default fcb, or go old-school and ask a question and read the reply from console. Not sure how much smaller it would be though. 5kB for what you have now is ridiculous. Maybe switch to ACK? You'll get 8080 code, but that's good enough 99% of the time, especially if you get a binary that's 75% smaller anyway.

 

Edited by ivop
Link to comment
Share on other sites

48 minutes ago, ivop said:

Here complete[0] is a zero-length array. Compiler should complain. See end of post.

z88dk has sizeof(int)==2, so this should work:

 

struct io_structure{
  unsigned char complete;
  unsigned char status;
  unsigned char command;
  unsigned char disk;
  unsigned int track;
  unsigned int sector;
  unsigned int dma;
};

 

Shouldn't variables, such as unsigned char complete, be assigned a size?  i.e.  unsigned char complete[1];

 

 

48 minutes ago, ivop said:

 

struct io_structute *io = (struct io_structure *)IOSTRUCTUREADDR;

 

Wow, that's pretty big, considering that dos2dir with the ACK is only ±1700 bytes.

Yes.  I am not thrilled about the size for what it does.  My thought was to program this in C so as to reduce the development time with the understanding the program would be "slightly" larger.

 

 

 

48 minutes ago, ivop said:

In the end it works the same, but IMHO it improves readability, and is less lines of code.

Visually it looks like you are calling a function (func(args)), but it's a reserved word in C and means return from function. It does not call anything. The parenthesis are now part of the expression that evaluates to the return value, and hence are superfluous.  It's not necessarily bad, but visually it does not convey the right meaning.

I'll get rid of the parentheses in return for the sake of readability, then.

 

48 minutes ago, ivop said:

Code size. A single call to bdos will be less code than your loop and calling conout.

Ok, maybe this should be a change in the future, then.  First, let's get this working.

 

48 minutes ago, ivop said:

I just installed z88dk and I must say I am pretty underwhelmed. It silently accepts wrong code and does not even issue a warning, like when calling functions with wrong arguments. gcc would say expected ‘unsigned char *’ but argument is of type ‘unsigned int’ , and the ACK says: (strict) illegal conversion of int to pointer, or when comparing chars to pointers (== on int and pointer), zero-length arrays ((strict) array size is 0), etc... It's difficult coding in a language you are not fluent in and the compiler does not tell you when you do things wrong.

Yeah, this is my first time using z88dk.

 

48 minutes ago, ivop said:

Another thing, I think your executable is also large because it contains all the code to parse the command line and populate **argv. You can probably get a smaller binary if you get the first command line argument directly from the default fcb, or go old-school and ask a question and read the reply from console. Not sure how much smaller it would be though. 5kB for what you have now is ridiculous. Maybe switch to ACK? You'll get 8080 code, but that's good enough 99% of the time, especially if you get a binary that's 75% smaller anyway.

 

I never considered the old-school method of asking a question as I was thinking more of parsing the command line. 

 

If I understand correctly, the command line should start at $0060 ?

 

 

I'll get it working then clean it up to try to make it smaller.

 

 

 

 

 

Link to comment
Share on other sites

Posted (edited)
1 hour ago, reifsnyderb said:

Shouldn't variables, such as unsigned char complete, be assigned a size?  i.e.  unsigned char complete[1];

No, that means an array of size one.

 

unsigned char foo;
unsigned char bar[1];
unsigned char *fubar = malloc(1);

foo is of type unsigned char
bar is of type unsigned char *
fubar is of type unsigned char *

the difference between bar and fubar is that bar points to somewhere in the bss segment, and fubar points to heap-allocated memory

also, be careful with defining multiple variables in one go:

char *apple, pear;

apple is a pointer of type char *, pear is of type char. that's why I type the * near the variable name instead of the type. some people would write

char* apple, pear;

which seem to imply both will be of the same type, which they are not.

More care is needed when const is involved:

const char *orange;
char * const peach;
const char * const mango;

orange is a pointer to a const char
peach is a const pointer to a char
mango is a const pointer to a const char

orange can be assigned to, but orange[42] = 'X' is invalid
peach cannot be assigned to, but peach[42] = 'X' is valid
mango cannot be assigned to, and mango[42] = 'X' is also invalid

peach and mango should be initialized at compile time

 

1 hour ago, reifsnyderb said:

I never considered the old-school method of asking a question as I was thinking more of parsing the command line. 

I specifically avoided the cumbersome CP/M command line and asked questions when I did the dos2tools :)

 

1 hour ago, reifsnyderb said:

If I understand correctly, the command line should start at $0060 ?

Yes. CCP should have filled the FCB in page zero with a sort-of-parsed command line, which means that the filename field is the first argument specified on the command line. Not sure what happens if you would specify the drive with a colon after it. It might be that CCP sets the drive number in the FCB instead, i.e.

 

format D --> filename = "D          " (10 spaces), drive = 0

format D : --> filename = "           " (11 spaces), drive = 4

 

(D : without the space, but otherwise the forum turns it into this emoji 😧 )

 

I didn't want to go down that rabbit hole, so I chose the ask questions way :)

 

As an added bonus, you can easily add a Drive X will be erased. Are You Sure? (Y/N) question.

 

edit: drive number in FCB counts from 1 (0 is current drive)

Edited by ivop
Link to comment
Share on other sites

Posted (edited)

I had to add a special command to the BIOS as it wasn't working right for some odd reason.  Since it really didn't take up much space, I figured making a special BIOS function wasn't a big deal.

 

Here's the latest code:

format.c

 

This code triggers a real drive to format.  However, for some reason, it appears that the Atari IO code is returning from SIO too early and not waiting for the drive to finish.

 

Here's the latest Atari SIO code:

atariio.asm

 

 

Edit to add:

 

Here's the CPM BIOS code:

CBIOS.asm

 

 

 

 

 

Edited by reifsnyderb
Link to comment
Share on other sites

Posted (edited)
39 minutes ago, reifsnyderb said:

I had to add a special command to the BIOS as it wasn't working right for some odd reason.  Since it really didn't take up much space, I figured making a special BIOS function wasn't a big deal.

 

Here's the latest code:

format.c 3.19 kB · 0 downloads

 

This code triggers a real drive to format.  However, for some reason, it appears that the Atari IO code is returning from SIO too early and not waiting for the drive to finish.

 

Here's the latest Atari SIO code:

atariio.asm 22.77 kB · 0 downloads

Congrats on getting it working!

 

I just tested this:

 

#include <cpm.h>
void main(void) {
    bdos(9,"Hello, world\r\n$");
}

And that works. You could do away with printb and printb_asm. Make sure to end each string with a $ sign.

 

9 because cpm.h has a bug and is missing a define for WRITESTR.

 

Also, in CP/M \r should only move the cursor to the beginning of the line (x position = 0). \n should advance to the next line but leave the x position at where it currently is. Two newlines could be shortened as "\r\n\n$"

 

Quote

However, for some reason, it appears that the Atari IO code is returning from SIO too early and not waiting for the drive to finish.

I vaguely remember something from back in the eighties that I stumbled upon that, too, but not sure how I fixed that. I'll think about it.

 

Edit: file size of Hello, world:

 

z8ddk: 4983

ACK: 467

 

Edited by ivop
Link to comment
Share on other sites

8 minutes ago, ivop said:

Congrats on getting it working!

Well, it's getting closer but not quite working yet.  The code to clear the directory and boot sector works by itself.  So, I think the basic format command just needs to have one more issue fixed.

 

 

8 minutes ago, ivop said:

I just tested this:

 

#include <cpm.h>
void main(void) {
    bdos(9,"Hello, world\r\n$");
}

And that works. You could do away with printb and printb_asm. Make sure to end each string with a $ sign.

Thanks!  I'll have to try it once the command works.

 

8 minutes ago, ivop said:

9 because cpm.h has a bug and is missing a define for WRITESTR.

 

Also, in CP/M \r should only move the cursor to the beginning of the line (x position = 0). \n should advance to the next line but leave the x position at where it currently is. Two newlines could be shortened as "\r\n\n$"

There is something that had to be cleaned up about the \r and \n.  I think \r is doing both a return and line feed.  It's in the source code somewhere.  Maybe it needs adjusted....

 

8 minutes ago, ivop said:

I vaguely remember something from back in the eighties that I stumbled upon that, too, but not sure how I fixed that. I'll think about it.

 

Edit: file size of Hello, world:

 

z8ddk: 4983

ACK: 467

 

 

Link to comment
Share on other sites

Posted (edited)
17 minutes ago, reifsnyderb said:

Well, it's getting closer but not quite working yet.  The code to clear the directory and boot sector works by itself.  So, I think the basic format command just needs to have one more issue fixed.

Not related, but looking over your code, I found this:

 

    LDA     #$7F                ; Set number of bytes to transfer
    STA     DBYTLO
    LDA     #$00
    STA     DBYTHI

    LDA     #$80                ; Set disk sector size
    STA     DBYTLO
    LDA     #$00
    STA     DBYTHI

 

Probably just an oversight, but the first time setting DBYTLO/HI can be removed.

 

I was comparing your code to what DOS 2.5 does (fms.zip here https://forums.atariage.com/topic/130992-here/?do=findComment&comment=2622222 , dup.zip a few posts down where the actual format command is called via CIO) and I don't see any obvious differences. If I understand you correctly, in your case SIOV returns when the drive is still busy formatting, right?

 

Edited by ivop
Link to comment
Share on other sites

Posted (edited)
7 minutes ago, ivop said:

Not related, but looking over your code, I found this:

 

    LDA     #$7F                ; Set number of bytes to transfer
    STA     DBYTLO
    LDA     #$00
    STA     DBYTHI

    LDA     #$80                ; Set disk sector size
    STA     DBYTLO
    LDA     #$00
    STA     DBYTHI

 

Probably just an oversight, but the first time setting DBYTLO/HI can be removed.

Yeah, thanks for finding that.  It's now removed.

 

7 minutes ago, ivop said:

I was comparing your code to what DOS 2.5 does (fms.zip here https://forums.atariage.com/topic/130992-here/?do=findComment&comment=2622222 , dup.zip a few posts down where the actual format command is called via CIO) and I don't see any obvious differences. If I understand you correctly, in your case SIOV returns when the drive is still busy formatting, right?

 

It was but that problem is now fixed.  It turns out format is really a type of read command.  lol    (https://forums.atariage.com/topic/367343-formatting-a-disk-via-siov/ )

 

 

There is still another problem.  I was using a real drive for B: and just switched over to an SIO2PC B: so I can look at the ATR and see if something odd happened.

 

 

 

 

Edited by reifsnyderb
Link to comment
Share on other sites

44 minutes ago, reifsnyderb said:

Yeah, thanks for finding that.  It's now removed.

 

It was but that problem is now fixed.  It turns out format is really a type of read command.  lol    (https://forums.atariage.com/topic/367343-formatting-a-disk-via-siov/ )

LOL, I just found this is in DOS.SYS in the format routine:

     LDY #$40    ;TELL SIO RECIEVING DATA
 

Glad that's solved.

 

Re format.c, instead of the for loops filling the sector buffer, you can:

 

1. move it to be a global variable. global variables are zeroed as per the C standard:

 

From section 3.5.7 of the C89 standard

        If an object that has static storage duration is not initialized explicitly, it is initialized implicitly as if every member that has arithmetic type were assigned 0 and every member that has pointer type were assigned a null pointer constant.

 

So I assume zcc does that. Access is also easier in Z80 assembly if it's not a stack variable.

 

2. so, no need to fill it with zeroes, that for-loop can be removed

3. use memset(sector_buffer, 0xe5, 128) to fill with 0xe5

You have to include <string.h> for that. With a bit of luck their standard library contains a hand-coded Z80 assembly version of memset, which is bound to be smaller than your for loop.

 

44 minutes ago, reifsnyderb said:

There is still another problem.  I was using a real drive for B: and just switched over to an SIO2PC B: so I can look at the ATR and see if something odd happened.

What other problem is that?

 

Link to comment
Share on other sites

Ok.  I got back to it.  There were some problems with sector_buffer and I eventually discovered the pointer wasn't working right.  So, since I don't have to worry too much about memory management I just hard-coded the sector_buffer to $E000.  Admittedly, it can be done better.  But it works for now.  Over the short term, I am not too concerned about format taking up a little over 5k because it's more important that it works.

 

I just realized sysgen doesn't do what I thought it did and now I've got to write a sys.com program to write the boot sectors to a disk.  <sigh>

 

On the positive note, if I take the format.com source code, cherry pick the working stuff, and set it up to read sectors from one disk to write the sectors to another, it shouldn't take too long.  The hard stuff is done.  I should also be able to read everything into a buffer to send it to the destination drive.  I suppose it should be designed to accommodate a single drive system, too.  But, that can come a little later.

 

Here's the format.com source code.  Yes, it can be improved but it works for now.

format.c

 

Oh, yeah, I successfully tested it with a real 1050 and a real floppy disk.   🙂

 

 

 

 

  • Like 6
Link to comment
Share on other sites

Posted (edited)
2 hours ago, reifsnyderb said:

Ok.  I got back to it.  There were some problems with sector_buffer and I eventually discovered the pointer wasn't working right.  So, since I don't have to worry too much about memory management I just hard-coded the sector_buffer to $E000.  Admittedly, it can be done better.  But it works for now.  Over the short term, I am not too concerned about format taking up a little over 5k because it's more important that it works.

 

I just realized sysgen doesn't do what I thought it did and now I've got to write a sys.com program to write the boot sectors to a disk.  <sigh>

 

On the positive note, if I take the format.com source code, cherry pick the working stuff, and set it up to read sectors from one disk to write the sectors to another, it shouldn't take too long.

But that's exactly what sysgen does. It copies the three boot tracks from one drive to the other. What else do you want it to do?

Edited by ivop
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...