Jump to content
IGNORED

Writing a sector copier cart, need some info.


Recommended Posts

Hey guys,

 

Am putting together an 8K sector copier cart (called tiny-copy) that can be plopped e.g. into an Ultimate 1MB BASIC slot.

 

I have most of the code written, but am just curious:

 

* Does anyone have code to detect RAM expansion options?

* also does anyone have code to handle transitioning to high-speed I/O for drives that support it? @Mathy   ???

 

I will be posting the result up to github soon.

 

-Thom

Link to comment
Share on other sites

Yes: leave it to the OS, not least since the volume may not be hosted by a serial device (PBI hosted ATR, HDD partition, etc).

 

Extended memory detection:

 

http://atariki.krap.pl/index.php/Obsługa_standardowego_rozszerzenia_pamięci_RAM

 

You might also want to check for SDX and branch to detection code which uses the SDX bank table if present in order not to nuke the DOS bank, RAMdisk, etc. See SDX programming manual.

  • Like 2
Link to comment
Share on other sites

Hi,

 

   I want to add sector copier functionality to ATR Maker Deluxe (it's an ABBUC software competition entry, so I can't publicly post the program, or sources yet), but if you are copying disks you could copy the sector data to a ramdisk file, rather than code for bank select management.

Link to comment
Share on other sites

9 minutes ago, E474 said:

Hi,

 

   I want to add sector copier functionality to ATR Maker Deluxe (it's an ABBUC software competition entry, so I can't publicly post the program, or sources yet), but if you are copying disks you could copy the sector data to a ramdisk file, rather than code for bank select management.

Sigh.

 

No, actually, I can't. This is intended to run from an 8K cart, entirely self contained without a DOS, so it uses SIOV wholly. So I have the whole machine to myself, ergo, I need to handle the bank switching myself.

 

-Thom

Edited by tschak909
Link to comment
Share on other sites

Yes: Hias' driver is built into the U1MB which is the target platform for the tool being developed. As I already suggested: keep serial drivers out of the application unless you want it to be useless with PBI hosted ATRs and hard disk partitions. The PBI BIOS has everything required, and even if the newer firmware with the driver is not present, the high-speed patched OS is. ;)

  • Like 3
Link to comment
Share on other sites

As part of my process of understanding the output of the percom disk block, I wrote a little tool to dump and display it:

 

/**
 * Read and dump percom block
 */

#include <stdio.h>
#include <stdlib.h>
#include <atari.h>
#include <6502.h>

struct _percom_block
{
  unsigned char num_tracks;
  unsigned char step_rate;
  unsigned short sectors_per_track;
  unsigned char num_sides;
  unsigned char density;
  unsigned short sector_size;
  unsigned char drive_present;
  unsigned char reserved1;
  unsigned char reserved2;
  unsigned char reserved3;
};

struct _percom_block percom_block;
unsigned char buf[12];

void main(void)
{
  struct regs r;
  OS.dcb.ddevic=0x31;
  OS.dcb.dunit=2;
  OS.dcb.dcomnd=0x4E;
  OS.dcb.dbuf=&buf;
  OS.dcb.dtimlo=0x0f;
  OS.dcb.dstats=0x40;
  OS.dcb.dbyt=12;

  r.pc=0xE459;
  _sys(&r);

  percom_block.num_tracks=buf[0];
  percom_block.step_rate=buf[1];
  percom_block.sectors_per_track=(buf[2]<<8)+buf[3];
  percom_block.num_sides=buf[4]+1;
  percom_block.density=buf[5];
  percom_block.sector_size=(buf[6]<<8)+buf[7];
  percom_block.drive_present=buf[8];

  printf("Percom Block Contents:\n");
  printf("----------------------\n");
  printf("num_tracks: %u\n",percom_block.num_tracks);
  printf("step_rate: %u\n",percom_block.step_rate);
  printf("sectors_per_track: %u\n",percom_block.sectors_per_track);
  printf("num_sides: %u\n",percom_block.num_sides);
  printf("density: %u\n",percom_block.density);
  printf("sector size: %u\n",percom_block.sector_size);
  printf("drive present? %u\n",percom_block.drive_present);
}

Example output of a DD 512 65535 sector disk:

D1:PERCOM
Percom Block Contents:
----------------------
num_tracks: 1
step_rate: 1
sectors_per_track: 65535
num_sides: 1
density: 0
sector size: 512
drive present? 255

Versus a 1050 formatted disk:

D1:PERCOM
Percom Block Contents:
----------------------
num_tracks: 40
step_rate: 1
sectors_per_track: 26
num_sides: 1
density: 4
sector size: 128
drive present? 255

 

You might ask, why I didn't just slam it right into the struct's buffer, the answer is that because Percom's controller was based on a 6809, the byte order is big endian, and therefore to use on a 6502, the bytes of the 16-bit values need to be swapped.

 

-Thom

  • Like 1
Link to comment
Share on other sites

Neat little project.  Just curious -- can Action! executables be put in cartridge format?  I don't recall seeing one, but offhand, seems like it should be possible.  Anyone know of one that already exists?  Do you have a size goal -- 1 to 2K maybe?  That would leave room for some other utilities. (?)

-Larry

Link to comment
Share on other sites

10 hours ago, tschak909 said:

@flashjazzcat silly question, can 512 byte sectored "partitions" be read with SIOV if the DBYT length is 512? Or does that require special handling?

Yes they can. Commonly such 512 byte sectors will be hosted on some PBI device anyway, and most IDE host adapters will ignore the buffer length passed via the DCB and simply transfer the full sector regardless (loops are often unrolled, etc, and observing the buffer length would be fiddly and superfluous).

 

Of course you should set the buffer size in the DCB anyway (since the tool need not care whether a volume is hosted on the serial or parallel bus), having obtained geometry information from the PERCOM block (which should provide the correct information regardless of where the volume is hosted, and if it does not, you can assume the disk is single-density).

 

Link to comment
Share on other sites

2 hours ago, Larry said:

Neat little project.  Just curious -- can Action! executables be put in cartridge format?  I don't recall seeing one, but offhand, seems like it should be possible.  Anyone know of one that already exists?  Do you have a size goal -- 1 to 2K maybe?  That would leave room for some other utilities. (?)

-Larry

They can, if you’re careful as to the constructs you use.

  • Like 1
Link to comment
Share on other sites

@Larry basically, you have to be aware of your memory map. Cartridges are ROMmed code, and especially in ACTION! you have to carefully make sure that you specify RAM vs ROM addressing with your variables.

 

In ROM programs, the address space is bifurcated, from the point of the linker, there are multiple segments of memory for things like CODE, DATA, RODATA, BSS, etc, and the parts that don't change get address offsets relative to the start of the ROM space, while parts that remain in RAM get address offsets relative to the requested start address (in my case $0600)

 

With C, this is done by either explicitly setting segments, or, if you don't need specific address alignments (I don't, as I am not using a charset for example), then I can either specify a variable stay in ROM by doing:

 

const unsigned char some_table[512]={ 0x00, 0x01, 0x02, 0x03 ... };

 

versus something that will start in ROM, but be copied to RAM by the runtime:

 

unsigned char buf[512]={0x00, 0x01, 0x02 ...};

In C, this is put into the initialized data segment (commonly called DATA), and while it is stored on ROM, the contents are pushed over when the program starts, before being handed off to main().

 

Whereas if something is defined as:

unsigned char some_state;

This is what is known as uninitialized data, and in C this goes into what is called the BSS segment. The memory space is reserved relative to the starting address of your program.

 

(and then there is heap that is allocated/freed over the course of the program, but only if malloc/free are used)

 

As far as I know, ACTION! does not natively do dynamic memory allocation, but it can be implemented. (Honestly, on an 8-bit system, unless you are using something that stays resident in e.g. SpartaDOS X, using dynamic memory allocation is unneeded overhead IMHO)

 

In my case, this cartridge does NOT use CIO, so it does not need an FMS, so it starts up almost immediately (it is not a diagnostic cart, so the OS initializes.), and because of that, the cartridge can literally use memory starting at about $0600 (actually probably as low as $0500), for program temporary variables, and use all of addressable ram for my purposes.

 

Since I am hoping to detect and utilize XL/XE type expansions, this means that most disks will be done in one pass.

 

If no ram expansion, no big deal, a 90K disk will take about 2 passes.

 

It might seem silly as to why I am doing this, but I have two reasons:

 

(1) I saw a hole that I thought needed to be filled, a sector copier that could fit on an 8K cart and therefore be loaded from a U1MB slot really quickly.

(2) More examples in C of how to do Atari specific things, Nina's Diary, and Mr. Robot Formatter also fall into this.

 

And ironically, if you include PLATOTERM in this, it serves as a spectrum between something ultra-portable, and something extremely machine specific being written in the same language. It is literally why C has been my lingua franca for almost three decades now, despite having about 40 other languages buried in my skull that I also use. :)

 

Edited by tschak909
  • Like 3
Link to comment
Share on other sites

8 hours ago, flashjazzcat said:

Yes they can. Commonly such 512 byte sectors will be hosted on some PBI device anyway, and most IDE host adapters will ignore the buffer length passed via the DCB and simply transfer the full sector regardless (loops are often unrolled, etc, and observing the buffer length would be fiddly and superfluous).

 

This appears to me like a recipe for desaster. Give back more bytes than the program requested, overrunning buffers?

Link to comment
Share on other sites

16 minutes ago, sanny said:

This appears to me like a recipe for desaster. Give back more bytes than the program requested, overrunning buffers?

I think if an application requests a raw sector from a quad-density volume without allocating sufficient memory for the data (having established disk density using the proper methods), it deserves everything it gets. What would be your proposed alternative?

 

  • Like 1
Link to comment
Share on other sites

So, with a bit of assembler massaging, was able to take the memory bank detection code above, and pull it in to be used by cc65.

 


        .include "atari.inc"
        .export _mem_detect, _banks, _bsav

        ;; Detect extended memory banks for XL/XE systems.
        ;; Borrowed from: http://atariki.krap.pl/index.php/Obs%C5%82uga_standardowego_rozszerzenia_pami%C4%99ci_RAM

ext_b = $4000; anything in the range of $ 4000- $ 7FFF
portb = $d301

; procedure
_mem_detect:
       lda portb
       pha

       lda #$ff
       sta portb

       lda ext_b
       pha

       ldx #$0f; remember bytes ext (from 16 blocks of 64k)
_p0:   jsr setpb
       lda ext_b
       sta _bsav, x
       dex
       bpl _p0

       ldx #$0f; reset them (in a separate loop, because it is not known
_p1:   jsr setpb; which PORTB bit combinations choose the same banks)
       lda #$00
       sta ext_b
       dex
       bpl _p1

       stx portb; elimination of basic memory
       stx ext_b
       stx $00; necessary for some extensions up to 256k

       ldy #$00; loop counting blocks 64k
       ldx #$0f
_p2:   jsr setpb
       lda ext_b; if ext_b is nonzero, the 64k block is already counted
       bne _n2

       dec ext_b; otherwise mark as counted

       lda ext_b; check if checked; if not -> something is wrong with the equipment
       bpl _n2

       lda portb; enter PORTB into the array for bank 0
       sta _banks, y
       eor #%00000100; complete the values for banks 1, 2, 3
       sta _banks + 1, y
       eor #%00001100
       sta _banks + 2, y
       eor #%00000100
       sta _banks + 3, y
       iny
       iny
       iny
       iny

_n2:   dex
       bpl _p2

       ldx #$0f; restore content ext
_p3:   jsr setpb
       lda _bsav, x
       sta ext_b
       dex
       bpl _p3

       stx portb; X = $ FF

       pla
       sta ext_b

       pla
       sta portb
       tya                      ; so it can easily be picked up as return value
       rts

; subroutines
setpb: txa ; bit order change:% 0000dcba ->% cba000d0
       lsr
       ror
       ror
       ror
       adc #$01 ; setting bit 1 depending on the state of C
       ora #$01 ; setting the OS ROM control bit to the default value
       sta portb
       rts

; variables
_banks: .res 64
_bsav:  .res 16

added a tya before the rts so that the # of banks will be in the accumulator, and be passed as a return value back from mem_detect.

 

Not sure I need bsav exported, I can probably hide that again.

 

And an example of calling from C.

 

/**
 * Mem detect harness
 */

#include <stdio.h>

extern unsigned char mem_detect(void);
extern unsigned char banks[64];

void main(void)
{
  unsigned char num_banks = mem_detect();
  unsigned char i;

  printf("\n\n");
  printf("mem detect\n");
  printf("----------\n\n");
  printf("num_banks: %d\n",num_banks);

  for (i=0;i<num_banks;i++)
    {
      printf("bank[%d]=0x%02x\n",i,banks[i]);
    }

  printf("\n\n");
}

 

banks[] contains an array of up to 64 entries containing the necessary complete PORTB values, making bank switching REALLY EASY.

 

as can be seen from this testing harness, this output from being set to RAMBO 1088K:

 

mem detect
----------

num_banks: 64
bank[0]=0xe3
bank[1]=0xe7
bank[2]=0xeb
bank[3]=0xef
bank[4]=0xc3
bank[5]=0xc7
bank[6]=0xcb
bank[7]=0xcf
bank[8]=0xa3
bank[9]=0xa7
bank[10]=0xab
bank[11]=0xaf
bank[12]=0x83
bank[13]=0x87
bank[14]=0x8b
bank[15]=0x8f
bank[16]=0x63
bank[17]=0x67
bank[18]=0x6b
bank[19]=0x6f
bank[20]=0x43
bank[21]=0x47
bank[22]=0x4b
bank[23]=0x4f
bank[24]=0x23
bank[25]=0x27
bank[26]=0x2b
bank[27]=0x2f
bank[28]=0x03
bank[29]=0x07
bank[30]=0x0b
bank[31]=0x0f
bank[32]=0xe1
bank[33]=0xe5
bank[34]=0xe9
bank[35]=0xed
bank[36]=0xc1
bank[37]=0xc5
bank[38]=0xc9
bank[39]=0xcd
bank[40]=0xa1
bank[41]=0xa5
bank[42]=0xa9
bank[43]=0xad
bank[44]=0x81
bank[45]=0x85
bank[46]=0x89
bank[47]=0x8d
bank[48]=0x61
bank[49]=0x65
bank[50]=0x69
bank[51]=0x6d
bank[52]=0x41
bank[53]=0x45
bank[54]=0x49
bank[55]=0x4d
bank[56]=0x21
bank[57]=0x25
bank[58]=0x29
bank[59]=0x2d
bank[60]=0x01
bank[61]=0x05
bank[62]=0x09
bank[63]=0x0d

-Thom

Link to comment
Share on other sites

This looks really cool, and something I could use. Question, can the copier detect the size of the sector of the disk automatically? I'm probably doing something wrong, but the last time I tried to back up some of my personal disks I ran into issues not know which disks are SD, DD, or ED so I missed data. 

 

I have a mix of SpartaDOS, DOS 3, DOS 2.5, and MyDOS disks. I'm sure there are others in there...

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...