mirror of
https://github.com/deater/dos33fsprogs.git
synced 2025-01-12 00:30:31 +00:00
dos33: update for a new SHOWFREE command
This commit is contained in:
parent
05ac8c64d9
commit
f45fff6c55
95
chiptune_player/README.chiptune
Normal file
95
chiptune_player/README.chiptune
Normal file
@ -0,0 +1,95 @@
|
||||
The Challenges of an Apple II chiptune player.
|
||||
|
||||
The goal is to design a chiptune player that can play large
|
||||
(150k+ uncompressed) chiptune files on an Apple II with 48k of RAM
|
||||
and a Mockingboard sound card.
|
||||
|
||||
An interrupt routine wakes at 50Hz to write the registers and a few other
|
||||
houskeeping things.
|
||||
|
||||
Not enough RAM to hold full raw ym5 sound data (one byte for each of 14
|
||||
registers, every 50Hz). This compresses amazingly. Using LZ4 by at
|
||||
least a factor of 10. But it won't fit all in RAM so we have to load
|
||||
the full file from disk (no way to do disk I/O, disk I/O disables interrupts)
|
||||
then decompress in chunks. So we need room for both the compressed file
|
||||
plus uncompressed data.
|
||||
|
||||
The problem is decompression also takes a while, longer than the 50Hz.
|
||||
So if we just decompress the next chunk when needed the sound will noticibly
|
||||
pause for a fraction of a second.
|
||||
|
||||
One solution to that is to have two decompress areas and flip between them,
|
||||
decompressing in the background to one while the other is playing. The problem
|
||||
is splitting the decompressed data into smaller chunks like this is that
|
||||
it doesn't compress as well so it takes up more disk/memory space
|
||||
for the raw file.
|
||||
|
||||
|
||||
|
||||
Memory Map
|
||||
(not to scale)
|
||||
|
||||
------- $ffff
|
||||
| ROM/IO|
|
||||
------- $c000
|
||||
|DOS3.3 |
|
||||
-------| $9600
|
||||
| |
|
||||
| |
|
||||
| FREE |
|
||||
| |
|
||||
| |
|
||||
|------- $0c00
|
||||
|GR pg 1|
|
||||
|------- $0800
|
||||
|GR pg 0|
|
||||
------- $0400
|
||||
| |
|
||||
------- $0200
|
||||
|stack |
|
||||
------- $0100
|
||||
|zero pg|
|
||||
------- $0000
|
||||
|
||||
|
||||
|
||||
Sizes
|
||||
|
||||
time ym5 KRW(3) KRW(2)
|
||||
~~~~ ~~~ ~~~~~~ ~~~~~~
|
||||
KORO.KRW 0:54 ? 2740
|
||||
FIGHTING.KRW 1:40 ? 3086
|
||||
CAMOUFLAGE.KRW 1:32 1162 4054
|
||||
DEMO4.KRW 2:05 1393 4061
|
||||
SDEMO.KRW 2:12 1635 5266
|
||||
CHRISTMAS.KRW 1:32 1751 4975
|
||||
SPUTNIK.KRW 2:05 2164 8422
|
||||
DEATH2.KRW 2:27 2560 8064
|
||||
CRMOROS.KRW 1:29 2566 8045
|
||||
TECHNO.KRW 2:23 2630 8934
|
||||
WAVE.KRW 2:52 2655 8368
|
||||
LYRA2.KRW 3:04 2870 9826
|
||||
INTRO2.KRW 2:59 3217 9214
|
||||
ROBOT.KRW 1:26 3448 7724
|
||||
UNIVERSE.KRW 1:49 4320 9990
|
||||
NEURO.KRW 3:47 8681 22376
|
||||
AXELF.KRW 10:55 9692 47989
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
Interesting bugs that were hard to debug:
|
||||
|
||||
+ Bug in qkumba's LZ4 decoder, only happened when a copy-block size was
|
||||
exactly a multiple of 256, in which case it would copy
|
||||
an extra time.
|
||||
|
||||
+ Bug where the box-drawing was starting at 0 rather than at Y.
|
||||
Turns out I was padding the filename buffer with A0 but going
|
||||
one too far and it was writing A0 to the first byte of the
|
||||
hlin routine, and A0 is a LDY # instruction.
|
@ -1144,6 +1144,7 @@ repeat_catalog:
|
||||
printf("\tSize in sectors = %i\n",
|
||||
sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_L)]+
|
||||
(sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_H)]<<8));
|
||||
|
||||
repeat_tsl:
|
||||
printf("\tT/S List $%02X/$%02X:\n",ts_t,ts_s);
|
||||
if (deleted) goto continue_dump;
|
||||
@ -1178,6 +1179,234 @@ continue_dump:;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dos33_showfree(int fd) {
|
||||
|
||||
int num_tracks,catalog_t,catalog_s,file,ts_t,ts_s,ts_total;
|
||||
int track,sector;
|
||||
int i,j;
|
||||
int deleted=0;
|
||||
char temp_string[BUFSIZ];
|
||||
unsigned char tslist[BYTES_PER_SECTOR];
|
||||
int result;
|
||||
|
||||
int sectors_per_track;
|
||||
int catalog_used;
|
||||
int next_letter='a';
|
||||
struct file_key_type {
|
||||
int ch;
|
||||
char *filename;
|
||||
} file_key[100];
|
||||
int num_files=0;
|
||||
|
||||
|
||||
unsigned char usage[35][16];
|
||||
|
||||
for(i=0;i<35;i++) for(j=0;j<16;j++) usage[i][j]=0;
|
||||
|
||||
/* Read Track 1 Sector 9 */
|
||||
lseek(fd,DISK_OFFSET(1,9),SEEK_SET);
|
||||
result=read(fd,sector_buffer,BYTES_PER_SECTOR);
|
||||
|
||||
printf("Finding name of startup file, Track 1 Sector 9 offset $75\n");
|
||||
printf("Startup Filename: ");
|
||||
for(i=0;i<30;i++) {
|
||||
printf("%c",sector_buffer[0x75+i]&0x7f);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
dos33_read_vtoc(fd);
|
||||
|
||||
printf("\n");
|
||||
printf("VTOC INFORMATION:\n");
|
||||
catalog_t=sector_buffer[VTOC_CATALOG_T];
|
||||
catalog_s=sector_buffer[VTOC_CATALOG_S];
|
||||
printf("\tFirst Catalog = %02X/%02X\n",catalog_t,catalog_s);
|
||||
printf("\tDOS RELEASE = 3.%i\n",sector_buffer[VTOC_DOS_RELEASE]);
|
||||
printf("\tDISK VOLUME = %i\n",sector_buffer[VTOC_DISK_VOLUME]);
|
||||
ts_total=sector_buffer[VTOC_MAX_TS_PAIRS];
|
||||
printf("\tT/S pairs that will fit in T/S List = %i\n",ts_total);
|
||||
|
||||
printf("\tLast track where sectors were allocated = $%02X\n",
|
||||
sector_buffer[VTOC_LAST_ALLOC_T]);
|
||||
printf("\tDirection of track allocation = %i\n",
|
||||
sector_buffer[VTOC_ALLOC_DIRECT]);
|
||||
|
||||
num_tracks=sector_buffer[VTOC_NUM_TRACKS];
|
||||
printf("\tNumber of tracks per disk = %i\n",num_tracks);
|
||||
printf("\tNumber of sectors per track = %i\n",
|
||||
sector_buffer[VTOC_S_PER_TRACK]);
|
||||
sectors_per_track=sector_buffer[VTOC_S_PER_TRACK];
|
||||
|
||||
printf("\tNumber of bytes per sector = %i\n",
|
||||
(sector_buffer[VTOC_BYTES_PER_SH]<<8)+
|
||||
sector_buffer[VTOC_BYTES_PER_SL]);
|
||||
|
||||
printf("\nFree sector bitmap:\n\n");
|
||||
printf("\t 1111111111111111222\n");
|
||||
printf("\t0123456789ABCDEF0123456789ABCDEF012\n");
|
||||
|
||||
for(j=0;j<sectors_per_track;j++) {
|
||||
printf("$%01X:\t",j);
|
||||
for(i=0;i<num_tracks;i++) {
|
||||
|
||||
if (j<8) {
|
||||
if ((sector_buffer[VTOC_FREE_BITMAPS+(i*4)]<<j)&0x80) {
|
||||
printf(".");
|
||||
}
|
||||
else {
|
||||
printf("U");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if ((sector_buffer[VTOC_FREE_BITMAPS+(i*4)+1]<<j)&0x80) {
|
||||
printf(".");
|
||||
}
|
||||
else {
|
||||
printf("U");
|
||||
}
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
printf("Key: U=used, .=free\n\n");
|
||||
|
||||
/* Reserve DOS */
|
||||
for(i=0;i<3;i++) for(j=0;j<16;j++) usage[i][j]='$';
|
||||
|
||||
/* Reserve CATALOG (not all used?) */
|
||||
i=0x11;
|
||||
for(j=0;j<16;j++) usage[i][j]='#';
|
||||
|
||||
|
||||
repeat_catalog:
|
||||
|
||||
catalog_used=0;
|
||||
|
||||
// printf("\nCatalog Sector $%02X/$%02x\n",catalog_t,catalog_s);
|
||||
lseek(fd,DISK_OFFSET(catalog_t,catalog_s),SEEK_SET);
|
||||
result=read(fd,sector_buffer,BYTES_PER_SECTOR);
|
||||
|
||||
|
||||
// dump_sector();
|
||||
|
||||
for(file=0;file<7;file++) {
|
||||
// printf("\n\n");
|
||||
|
||||
ts_t=sector_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_TS_LIST_T))];
|
||||
ts_s=sector_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_TS_LIST_S))];
|
||||
|
||||
// printf("%i+$%02X/$%02X - ",file,catalog_t,catalog_s);
|
||||
deleted=0;
|
||||
|
||||
if (ts_t==0xff) {
|
||||
printf("**DELETED** ");
|
||||
deleted=1;
|
||||
ts_t=sector_buffer[(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_NAME+0x1e))];
|
||||
}
|
||||
|
||||
if (ts_t==0x00) {
|
||||
// printf("UNUSED!\n");
|
||||
goto continue_dump;
|
||||
}
|
||||
|
||||
strncpy(temp_string,
|
||||
dos33_filename_to_ascii(temp_string,
|
||||
sector_buffer+(CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_NAME)),30),
|
||||
BUFSIZ);
|
||||
|
||||
for(i=0;i<strlen(temp_string);i++) {
|
||||
if (temp_string[i]<0x20) {
|
||||
printf("^%c",temp_string[i]+0x40);
|
||||
}
|
||||
else {
|
||||
printf("%c",temp_string[i]);
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
// printf("\tLocked = %s\n",
|
||||
// sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE)+FILE_TYPE]>0x7f?
|
||||
// "YES":"NO");
|
||||
// printf("\tType = %c\n",
|
||||
// dos33_file_type(sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE)+FILE_TYPE]));
|
||||
// printf("\tSize in sectors = %i\n",
|
||||
// sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_L)]+
|
||||
// (sector_buffer[CATALOG_FILE_LIST+(file*CATALOG_ENTRY_SIZE+FILE_SIZE_H)]<<8));
|
||||
|
||||
if (!deleted) {
|
||||
catalog_used++;
|
||||
usage[catalog_t][catalog_s]='@';
|
||||
}
|
||||
|
||||
repeat_tsl:
|
||||
// printf("\tT/S List $%02X/$%02X:\n",ts_t,ts_s);
|
||||
if (deleted) goto continue_dump;
|
||||
|
||||
usage[ts_t][ts_s]=next_letter;
|
||||
file_key[num_files].ch=next_letter;
|
||||
file_key[num_files].filename=strdup(temp_string);
|
||||
|
||||
num_files++;
|
||||
|
||||
|
||||
lseek(fd,DISK_OFFSET(ts_t,ts_s),SEEK_SET);
|
||||
result=read(fd,&tslist,BYTES_PER_SECTOR);
|
||||
|
||||
for(i=0;i<ts_total;i++) {
|
||||
track=tslist[TSL_LIST+(i*TSL_ENTRY_SIZE)];
|
||||
sector=tslist[TSL_LIST+(i*TSL_ENTRY_SIZE)+1];
|
||||
if ((track==0) && (sector==0)) {
|
||||
//printf(".");
|
||||
}
|
||||
else {
|
||||
// printf("\n\t\t%02X/%02X",track,sector);
|
||||
usage[track][sector]=toupper(next_letter);
|
||||
}
|
||||
}
|
||||
ts_t=tslist[TSL_NEXT_TRACK];
|
||||
ts_s=tslist[TSL_NEXT_SECTOR];
|
||||
|
||||
if (!((ts_s==0) && (ts_t==0))) goto repeat_tsl;
|
||||
continue_dump:;
|
||||
|
||||
next_letter++;
|
||||
}
|
||||
|
||||
catalog_t=sector_buffer[CATALOG_NEXT_T];
|
||||
catalog_s=sector_buffer[CATALOG_NEXT_S];
|
||||
|
||||
if (catalog_s!=0) {
|
||||
file=0;
|
||||
goto repeat_catalog;
|
||||
}
|
||||
|
||||
printf("\n");
|
||||
|
||||
if (result<0) fprintf(stderr,"Error on I/O\n");
|
||||
|
||||
printf("\nDetailed sector bitmap:\n\n");
|
||||
printf("\t 1111111111111111222\n");
|
||||
printf("\t0123456789ABCDEF0123456789ABCDEF012\n");
|
||||
|
||||
for(j=0;j<sectors_per_track;j++) {
|
||||
printf("$%01X:\t",j);
|
||||
for(i=0;i<num_tracks;i++) {
|
||||
if (usage[i][j]==0) printf(".");
|
||||
else printf("%c",usage[i][j]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
}
|
||||
|
||||
printf("Key: $=DOS, @=catalog used, #=catalog reserved, .=free\n\n");
|
||||
for(i=0;i<num_files;i++) {
|
||||
printf("\t%c %s\n",file_key[i].ch,file_key[i].filename);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ??? */
|
||||
static int dos33_rename_hello(int fd, char *new_name) {
|
||||
|
||||
@ -1248,8 +1477,9 @@ static void display_help(char *name, int version_only) {
|
||||
#define COMMAND_HELLO 11
|
||||
#define COMMAND_BSAVE 12
|
||||
#define COMMAND_BLOAD 13
|
||||
#define COMMAND_SHOWFREE 14
|
||||
|
||||
#define MAX_COMMAND 14
|
||||
#define MAX_COMMAND 15
|
||||
#define COMMAND_UNKNOWN 255
|
||||
|
||||
static struct command_type {
|
||||
@ -1269,6 +1499,7 @@ static struct command_type {
|
||||
{COMMAND_DUMP,"DUMP"},
|
||||
{COMMAND_HELLO,"HELLO"},
|
||||
{COMMAND_BSAVE,"BSAVE"},
|
||||
{COMMAND_SHOWFREE,"SHOWFREE"},
|
||||
};
|
||||
|
||||
static int lookup_command(char *name) {
|
||||
@ -1567,6 +1798,11 @@ int main(int argc, char **argv) {
|
||||
dos33_dump(dos_fd);
|
||||
break;
|
||||
|
||||
case COMMAND_SHOWFREE:
|
||||
printf("Showing Free %s!\n",image);
|
||||
dos33_showfree(dos_fd);
|
||||
break;
|
||||
|
||||
case COMMAND_LOCK:
|
||||
case COMMAND_UNLOCK:
|
||||
/* check and make sure we have apple_filename */
|
||||
|
Loading…
x
Reference in New Issue
Block a user