Jump to content
Harry Potter

cc65: best way to access the disk?

Recommended Posts

Hi!  I know about ANSI file commands.  I have a program I want to eventually port to the Atari 8-bit series.  It is written in cc65 C.  I could use the ANSI file functions, but I want to allocate more memory for documents, and they require extra overhead.  Is there a better way to access the disk from cc65 C code?  If not, I could create it, but I need some info on Atari DOS.

Share this post


Link to post
Share on other sites

Sounds like you're inventing imaginary limitations for yourself?!

Files are random access in nature so load them as you see fit.

Share this post


Link to post
Share on other sites

Just use CIO functions, write is an assembler module, then it's DOS independent

Share this post


Link to post
Share on other sites

There are two ways if you want to bypass functions provided by <stdio.h>

 

1. Use CIO as suggested above. You will be required to code in assembler, of course. You can google for more information on CIO. Perhaps you can look here. This is independent on file management system type. You can see how CIO is used to open a file here.

2. Access sectors of the disk directly using the resident disk handler. This would probably limit you to certain subset of file management systems. Then you might need to read Inside Atari DOS to get information on the DOS2 FMS.

 

As for option #1, the question is, if calling CIO would result in significantly smaller code. Perhaps when you will use only a small set of file-related functions. Option #2 is useful only when your software will work without any DOS. Such option is typically used (but not limited to) by specialized copy programs providing big memory buffer for copied objects, e.g. tape to disk copiers.

Share this post


Link to post
Share on other sites
Posted (edited)

Include _atarios.h and use the __iocb struct at the right memory location for IOCB0-7, and call CIOV.

 

Edit: read Mapping The Atari Revised Edition, De Re Atari, OS Manual, et cetera. All free to download. You don't need to read the whole books, obviously ;)

Edited by ivop

Share this post


Link to post
Share on other sites
Posted (edited)

cc65 won't help, CIO in assembler is up to you to write the code, you can pass buffers/variables

into the routines.

Something like this:- closes channel 1, opens a file, reads one line, closes the channel

Written in MAC/65 , but can easily be split into procs in cc65 assembler module.

 

10 LENGTH =  128
20 BUFFER =  $0600   ; CIO BUFFER
0100     .INCLUDE #D:HEADER.M65
0110     *=  $2000
0120     LDX #16     ; CHANNEL 1
0130     LDA #CLOSE
0140     STA ICCOM,X
0150     JSR CIOV    ; CLOSE CHANNEL 1
0160     LDA #OPEN   ; OPEN CHANNEL 1
0170     STA ICCOM,X
0180     LDA # <FNAME
0190     STA ICBAL,X
0200     LDA # >FNAME
0210     STA ICBAH,X
0220     LDA #0
0230     STA ICBLL,X
0240     STA ICBLH,X
0250     LDA #OREAD
0260     STA ICAX1,X
0270     LDA #0
0280     STA ICAX2
0290     JSR CIOV
0300     BMI ERROR
0310     JMP GET
0320 FNAME .BYTE "D:TEMP.TXT",$9B
0330 ERROR LDA #$FF
0340     RTS 
0350 GET LDA #GETREC ; READ LINE
0360     STA ICCOM,X
0370     LDA # <BUFFER
0380     STA ICBAL,X
0390     LDA # >BUFFER
0400     STA ICBAH,X
0410     LDA #LENGTH
0420     STA ICBLL,X
0430     LDA #0
0440     STA ICBLH,X
0450     JSR CIOV
0460     BMI ERROR
0470     LDA #CLOSE
0480     STA ICCOM,X
0490     JSR CIOV
0500     RTS 
0510     .OPT NO LIST

Edited by TGB1718

Share this post


Link to post
Share on other sites
4 minutes ago, Harry Potter said:

How do I call CIOV?

Either with a C function pointer (in line with doing everything in C), or inline assembly doing JSR CIOV (which is $E456).

Share this post


Link to post
Share on other sites
9 minutes ago, TGB1718 said:

cc65 won't help, CIO in assembler is up to you to write the code

With _atari_os.h, it's not. You can do everything in C, including calling CIOV. Perhaps function pointers for these vectors should be added to this header file.

 

Edit:

 

void (*CIOV)(void) = 0xe456;

 

call as:

 

    CIOV();

 

 

struct __iocb *IOCB0 = 0x0340;

struct __iocb *IOCB1 = 0x0350;

...

etc...

 

IOCB1->command = IOCB_OPEN;

etc...

 

CIOV();

 

Edited by ivop

Share this post


Link to post
Share on other sites
1 minute ago, Harry Potter said:

How do I pass the block # to CIOV()?

Darn, forgot about that. After setting the values through the struct pointer, you indeed need inline assembly to do LDX #$10 (IOCBnr * $10) and then JSR $E456. Sorry about that, _atarios.h is not complete yet. It could need a macro or inline function for that. Everything else I said is still valid. I hope ;)

 

Share this post


Link to post
Share on other sites

Thank you.  :)  BTW, do you recommend loading things into Low RAM using this function?  Including it in the .XEX file doesn't work.  :(

Share this post


Link to post
Share on other sites

If you are loading it once then in the xex, but if you repeatedly load different content then that would ok, but equally any address suits. 

Share this post


Link to post
Share on other sites
49 minutes ago, ivop said:

With _atari_os.h, it's not. You can do everything in C, including calling CIOV. Perhaps function pointers for these vectors should be added to this header file.

 

5 minutes ago, Harry Potter said:

How do I get an error # of a CIO call?

like this:-

ASM Module:-

; Export the start of program code
   .export _callciov
   .export _channel
   .export _result
ciov=$e456

    .proc _callciov: near
    .code
    _callciov:
     lda _channel
     clc
     rol a   ; channel * 16
     rol a
     rol a
     rol a
     tax
     jsr ciov
     sty _result

      rts
    .endproc
_channel: .byte 0
_result: .byte 0

 

"C" Module :-

 

#include <atari.h>
#include <_atarios.h>

extern char callciov(char);
extern char channel;
extern char result;
void main(void)
{

    channel=1;
    OS.iocb[1].command=IOCB_CLOSE;
    result=callciov(channel);

}
 

 

Edited by TGB1718

Share this post


Link to post
Share on other sites

Haha, another overlooked issue. The return value is in the Y register, and can be stored in inline assembly to a C variable by __asm__ ("sta %v", ciov_return_value);

 

Share this post


Link to post
Share on other sites
7 minutes ago, TGB1718 said:

OS.iocb[1].command=IOCB_CLOSE;

Cool, another way to access the IOCBs!

 

But extern channel? Then channel=1 in the main program, and call CIOV(channel) without using the passed variable at all? I don't get it. CIOV(4) won't work.

Edited by ivop

Share this post


Link to post
Share on other sites
6 minutes ago, ivop said:

But extern channel? Then channel=1 in the main program, and call CIOV(channel) without using the passed variable at all? I don't get it.

channel is defined in the .s module and exported to the c module, c module sets channel to 1, assembler

converts it to 16 (channel 1) and calls CIOV

Share this post


Link to post
Share on other sites

I love live coding in the AtariAge editor ;)

 

#define CIOV 0xe456

 

static inline /* optional */

unsigned char callciov(unsigned char channel) {

    unsigned char retval;

    channel <<= 4;

    __asm__ ("ldx %v", channel);

    __asm__ ("jsr %w", CIOV);

    __asm__ ("sty %v", retval);

    return retval;

}

 

Edit: improvements

Edited by ivop

Share this post


Link to post
Share on other sites
2 minutes ago, TGB1718 said:

channel is defined in the .s module and exported to the c module, c module sets channel to 1, assembler

converts it to 16 (channel 1) and calls CIOV

But your argument to the callciov() function is not used?

Edited by ivop

Share this post


Link to post
Share on other sites

it does

    lda _channel
     clc
     rol a   ; channel * 16
     rol a
     rol a
     rol a
     tax      <<<<< here channel now 16 in x register
     jsr ciov

Share this post


Link to post
Share on other sites
3 minutes ago, TGB1718 said:

it does

    lda _channel
     clc
     rol a   ; channel * 16
     rol a
     rol a
     rol a
     tax      <<<<< here channel now 16 in x register
     jsr ciov

But that's not the argument that's passed on by calling callciov(4), or is it? That's the global variable. Why do channel=1 in the main program otherwise in the first place? Seems like the argument to the function is moot.

 

Edited by ivop

Share this post


Link to post
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...