diff --git a/firmware/Makefile b/firmware/Makefile new file mode 100644 index 0000000000..9b38303be4 --- /dev/null +++ b/firmware/Makefile @@ -0,0 +1,47 @@ +# __________ __ ___. +# Open \______ \ ____ ____ | | _\_ |__ _______ ___ +# Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +# Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +# Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +# \/ \/ \/ \/ \/ +# $Id$ +# + +HPATH = /usr/local/sh-gcc/bin +CC = $(HPATH)/sh-elf-gcc +LD = $(HPATH)/sh-elf-ld +AR = $(HPATH)/sh-elf-ar +AS = $(HPATH)/sh-elf-as +OC = $(HPATH)/sh-elf-objcopy + +INCLUDES=-I. + +CFLAGS = -Os -Wall -m1 -nostdlib -Wstrict-prototypes -fomit-frame-pointer -fschedule-insns $(INCLUDES) +AFLAGS += -small -relax + +SRC := $(wildcard *.c) +OBJS := $(SRC:%.c=%.o) + +%.o: %.s + $(CC) -o $@ $(CFLAGS) $(INCLUDES) $(DEFS) -c $< + + +all : $(OBJS) # archos.mod # archos.asm + +archos.elf : $(OBJS) app.lds + $(CC) -nostdlib -o archos.elf $(OBJS) -lgcc -Tapp.lds -Wl,-Map,archos.map + +archos.bin : archos.elf + $(OC) -O binary archos.elf archos.bin + +archos.asm: archos.bin + sh2d -sh1 archos.bin > archos.asm + +archos.mod : archos.bin + scramble archos.bin archos.mod + +dist: + tar czvf dist.tar.gz Makefile main.c start.s app.lds + +clean: + -rm -f *.x *.i *.o *.elf *.bin *.map *.mod *.bak *~ diff --git a/firmware/app.lds b/firmware/app.lds new file mode 100644 index 0000000000..03bd1b2b54 --- /dev/null +++ b/firmware/app.lds @@ -0,0 +1,23 @@ +ENTRY(_start) +OUTPUT_FORMAT(elf32-sh) +SECTIONS +{ + .vectors 0x09000000 : + { + *(.vectors); + . = ALIGN(0x200); + *(.text.start) + *(.text) + *(.rodata) + } + + .bss : + { + _stack = . + 0x1000; + } + + .pad 0x0900C800 : + { + LONG(0); + } + } diff --git a/firmware/fat.c b/firmware/fat.c new file mode 100644 index 0000000000..235341f72d --- /dev/null +++ b/firmware/fat.c @@ -0,0 +1,1315 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include +#include +#include +#include +#include +#include + +#include "fakestorage.h" +#include "fat.h" +#include "debug.h" + +#define NUM_ROOT_DIR_ENTRIES 512 +#define NUM_FATS 2 +#define NUM_RESERVED_SECTORS 1 +#define NUM_BLOCKS 10000 + +struct dsksz2secperclus +{ + unsigned int disk_size; + unsigned int sec_per_cluster; +}; + +/* +** This is the table for FAT16 drives. NOTE that this table includes +** entries for disk sizes larger than 512 MB even though typically +** only the entries for disks < 512 MB in size are used. +** The way this table is accessed is to look for the first entry +** in the table for which the disk size is less than or equal +** to the DiskSize field in that table entry. For this table to +** work properly BPB_RsvdSecCnt must be 1, BPB_NumFATs +** must be 2, and BPB_RootEntCnt must be 512. Any of these values +** being different may require the first table entries DiskSize value +** to be changed otherwise the cluster count may be to low for FAT16. +*/ +struct dsksz2secperclus dsk_table_fat16 [] = +{ + { 8400, 0}, /* disks up to 4.1 MB, the 0 value for SecPerClusVal + trips an error */ + { 32680, 2}, /* disks up to 16 MB, 1k cluster */ + { 262144, 4}, /* disks up to 128 MB, 2k cluster */ + { 524288, 8}, /* disks up to 256 MB, 4k cluster */ + { 1048576, 16}, /* disks up to 512 MB, 8k cluster */ +/* The entries after this point are not used unless FAT16 is forced */ + { 2097152, 32}, /* disks up to 1 GB, 16k cluster */ + { 4194304, 64}, /* disks up to 2 GB, 32k cluster */ + { 0xFFFFFFFF, 0} /* any disk greater than 2GB, + 0 value for SecPerClusVal trips an error */ +}; + +int fat_num_rootdir_sectors(struct bpb *bpb); +int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster); +int fat_get_fatsize(struct bpb* bpb); +int fat_get_totsec(struct bpb* bpb); +int fat_get_rootdir_sector(struct bpb *bpb); +int fat_first_data_sector(struct bpb* bpb); +int fat_get_bpb(struct bpb *bpb); +int fat_bpb_is_sane(struct bpb *bpb); +int fat_create_fat(struct bpb* bpb); +int fat_dbg_read_block(char *name, unsigned char *buf); +int fat_flush_fat(struct bpb *bpb); +unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum); +int fat_update_entry(struct bpb *bpb, int entry, unsigned int val); +unsigned int fat_getcurrdostime(unsigned short *dosdate, + unsigned short *dostime, + unsigned char *dostenth); +int fat_create_root_dir(struct bpb *bpb); +int fat_create_dos_name(unsigned char *name, unsigned char *newname); +int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name); + +unsigned char *fat_cache[256]; +int fat_cache_dirty[256]; +char current_directory[256] = "\\"; +struct bpb *global_bpb; +struct disk_info di; + +extern int yyparse(void); + + +void prompt(void) +{ + printf("C:%s>", current_directory); +} + +#ifdef TEST_FAT +int main(int argc, char *argv[]) +{ + struct bpb bpb; + + memset(fat_cache, 0, sizeof(fat_cache)); + memset(fat_cache_dirty, 0, sizeof(fat_cache_dirty)); + + disk_init(NUM_BLOCKS); + + di.num_sectors = NUM_BLOCKS; + di.sec_per_track = 40; + di.num_heads = 250; + di.hidden_sectors = 0; + + if(read_disk("diskdump.dmp") < 0) + { + printf("*** Warning! The disk is uninitialized\n"); + } + else + { + fat_get_bpb(&bpb); + } + + global_bpb = &bpb; + prompt(); + yyparse(); + + dump_disk("diskdump.dmp"); + return 0; +} +#endif + +int fat_sec2cluster(struct bpb *bpb, unsigned int sec) +{ + int first_sec = fat_first_data_sector(bpb); + + if(sec < first_sec) + { + fprintf(stderr, "fat_sec2cluster() - Bad sector number (%d)\n", sec); + return -1; + } + + return ((sec - first_sec) / bpb->bpb_secperclus) + 2; +} + +int fat_last_cluster_in_chain(struct bpb *bpb, unsigned int cluster) +{ + int iseof = 0; + + switch(bpb->fat_type) + { + case FATTYPE_FAT12: + if(cluster >= 0x0ff8) + iseof = 1; + break; + case FATTYPE_FAT16: + if(cluster >= 0xfff8) + iseof = 1; + break; + case FATTYPE_FAT32: + if(cluster >= 0x0ffffff8) + iseof = 1; + break; + } + return iseof; +} + +int fat_cluster2sec(struct bpb *bpb, unsigned int cluster) +{ + int max_cluster = (fat_get_totsec(bpb) - fat_first_data_sector(bpb)) / + bpb->bpb_secperclus + 1; + + if(cluster > max_cluster) + { + fprintf(stderr, "fat_cluster2sec() - Bad cluster number (%d)\n", + cluster); + return -1; + } + + return fat_first_sector_of_cluster(bpb, cluster); +} + +int fat_first_sector_of_cluster(struct bpb *bpb, unsigned int cluster) +{ + return (cluster - 2) * bpb->bpb_secperclus + fat_first_data_sector(bpb); +} + +int fat_num_rootdir_sectors(struct bpb *bpb) +{ + return ((bpb->bpb_rootentcnt * 32) + (bpb->bpb_bytspersec - 1)) / + bpb->bpb_bytspersec; +} + +int fat_get_fatsize(struct bpb* bpb) +{ + if(bpb->bpb_fatsz16 != 0) + return bpb->bpb_fatsz16; + else + return bpb->bpb_fatsz32; +} + +int fat_get_totsec(struct bpb* bpb) +{ + if(bpb->bpb_totsec16 != 0) + return bpb->bpb_totsec16; + else + return bpb->bpb_totsec32; +} + +int fat_get_rootdir_sector(struct bpb *bpb) +{ + return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fat_get_fatsize(bpb); +} + +int fat_first_data_sector(struct bpb* bpb) +{ + int fatsz; + int rootdirsectors; + + fatsz = fat_get_fatsize(bpb); + + rootdirsectors = fat_num_rootdir_sectors(bpb); + + return bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz + rootdirsectors; +} + +int fat_format(struct disk_info *di, char *vol_name) +{ + unsigned char buf[BLOCK_SIZE]; + struct bpb bpb; + unsigned int root_dir_sectors; + unsigned int tmp1, tmp2; + int sec_per_clus = 0; + int fat_size; + int i = 0; + int err; + + while(di->num_sectors > dsk_table_fat16[i].disk_size) + { + i++; + } + + sec_per_clus = dsk_table_fat16[i].sec_per_cluster; + + if(sec_per_clus == 0) + { + fprintf(stderr, "fat_format() - Bad disk size (%u)\n", + di->num_sectors); + return -1; + } + + /* First calculate how many sectors we need for + the root directory */ + root_dir_sectors = ((NUM_ROOT_DIR_ENTRIES * 32) + + (BLOCK_SIZE - 1)) / BLOCK_SIZE; + + /* Now calculate the FAT size */ + tmp1 = di->num_sectors - (NUM_RESERVED_SECTORS + root_dir_sectors); + tmp2 = (256 * sec_per_clus) + NUM_FATS; + + fat_size = (tmp1 + (tmp2 - 1)) / tmp2; + + /* Now create the BPB. We must be careful, so we really make + it little endian. */ + memset(buf, 0xff, BLOCK_SIZE); + + strncpy(&buf[BS_OEMNAME], "MSWIN4.1", 8); + buf[BPB_BYTSPERSEC] = BLOCK_SIZE & 0xff; + buf[BPB_BYTSPERSEC+1] = BLOCK_SIZE >> 8; + buf[BPB_SECPERCLUS] = sec_per_clus; + buf[BPB_RSVDSECCNT] = 1; + buf[BPB_RSVDSECCNT+1] = 0; + buf[BPB_NUMFATS] = 2; + buf[BPB_ROOTENTCNT] = NUM_ROOT_DIR_ENTRIES & 0xff; + buf[BPB_ROOTENTCNT+1] = NUM_ROOT_DIR_ENTRIES >> 8; + buf[BPB_TOTSEC16] = di->num_sectors & 0xff; + buf[BPB_TOTSEC16+1] = di->num_sectors >> 8; + buf[BPB_MEDIA] = 0xf0; + buf[BPB_FATSZ16] = fat_size & 0xff; + buf[BPB_FATSZ16+1] = fat_size >> 8; + buf[BPB_SECPERTRK] = di->sec_per_track & 0xff; + buf[BPB_SECPERTRK+1] = di->sec_per_track >> 8; + buf[BPB_NUMHEADS] = di->num_heads & 0xff; + buf[BPB_NUMHEADS+1] = di->num_heads >> 8; + buf[BPB_HIDDSEC] = di->hidden_sectors & 0xff; + buf[BPB_HIDDSEC+1] = (di->hidden_sectors >> 8) & 0xff; + buf[BPB_HIDDSEC+2] = (di->hidden_sectors >> 16) & 0xff; + buf[BPB_HIDDSEC+3] = (di->hidden_sectors >> 24) & 0xff; + buf[BPB_TOTSEC32] = 0; + buf[BPB_TOTSEC32+1] = 0; + buf[BPB_TOTSEC32+2] = 0; + buf[BPB_TOTSEC32+3] = 0; + + buf[BS_DRVNUM] = 0; + buf[BS_RESERVED1] = 0; + buf[BS_BOOTSIG] = 0x29; + buf[BS_VOLID] = 0x78; + buf[BS_VOLID+1] = 0x56; + buf[BS_VOLID+2] = 0x34; + buf[BS_VOLID+3] = 0x12; + memset(&buf[BS_VOLLAB], ' ', 11); + strncpy(&buf[BS_VOLLAB], vol_name, MIN(11, strlen(vol_name)); + strncpy(&buf[BS_FILSYSTYPE], "FAT16 ", 8); + + /* The final signature */ + buf[BPB_LAST_WORD] = 0x55; + buf[BPB_LAST_WORD+1] = 0xaa; + + /* Now write the sector to disk */ + err = write_block(buf, 0); + + if(err < 0) + { + fprintf(stderr, "fat_format() - Couldn't write BSB (error code %i)\n", + err); + return -1; + } + + if(fat_get_bpb(&bpb) < 0) + { + fprintf(stderr, "fat_format() - Couldn't read BPB\n"); + return -1; + } + + if(fat_create_fat(&bpb) < 0) + { + fprintf(stderr, "fat_format() - Couldn't create FAT\n"); + return -1; + } + + if(fat_create_root_dir(&bpb) < 0) + { + fprintf(stderr, "fat_format() - Couldn't write root dir sector\n"); + return -1; + } + + return 0; +} + +int fat_get_bpb(struct bpb *bpb) +{ + unsigned char buf[BLOCK_SIZE]; + int err; + int fatsz; + int rootdirsectors; + int totsec; + int datasec; + int countofclusters; + + /* Read the sector */ + err = read_block(buf, 0); + if(err < 0) + { + fprintf(stderr, "fat_get_bpb() - Couldn't read BPB (error code %i)\n", + err); + return -1; + } + + memset(bpb, 0, sizeof(struct bpb)); + + strncpy(bpb->bs_oemname, &buf[BS_OEMNAME], 8); + bpb->bs_oemname[8] = 0; + + bpb->bpb_bytspersec = buf[BPB_BYTSPERSEC] | (buf[BPB_BYTSPERSEC+1] << 8); + bpb->bpb_secperclus = buf[BPB_SECPERCLUS]; + bpb->bpb_rsvdseccnt = buf[BPB_RSVDSECCNT] | (buf[BPB_RSVDSECCNT+1] << 8); + bpb->bpb_numfats = buf[BPB_NUMFATS]; + bpb->bpb_rootentcnt = buf[BPB_ROOTENTCNT] | (buf[BPB_ROOTENTCNT+1] << 8); + bpb->bpb_totsec16 = buf[BPB_TOTSEC16] | (buf[BPB_TOTSEC16+1] << 8); + bpb->bpb_media = buf[BPB_MEDIA]; + bpb->bpb_fatsz16 = buf[BPB_FATSZ16] | (buf[BPB_FATSZ16+1] << 8); + bpb->bpb_secpertrk = buf[BPB_SECPERTRK] | (buf[BPB_SECPERTRK+1] << 8); + bpb->bpb_numheads = buf[BPB_NUMHEADS] | (buf[BPB_NUMHEADS+1] << 8); + bpb->bpb_hiddsec = buf[BPB_HIDDSEC] | (buf[BPB_HIDDSEC+1] << 8) | + (buf[BPB_HIDDSEC+2] << 16) | (buf[BPB_HIDDSEC+3] << 24); + bpb->bpb_totsec32 = buf[BPB_TOTSEC32] | (buf[BPB_TOTSEC32+1] << 8) | + (buf[BPB_TOTSEC32+2] << 16) | (buf[BPB_TOTSEC32+3] << 24); + + bpb->bs_drvnum = buf[BS_DRVNUM]; + bpb->bs_bootsig = buf[BS_BOOTSIG]; + if(bpb->bs_bootsig == 0x29) + { + bpb->bs_volid = buf[BS_VOLID] | (buf[BS_VOLID+1] << 8) | + (buf[BS_VOLID+2] << 16) | (buf[BS_VOLID+3] << 24); + strncpy(bpb->bs_vollab, &buf[BS_VOLLAB], 11); + strncpy(bpb->bs_filsystype, &buf[BS_FILSYSTYPE], 8); + } + + bpb->bpb_fatsz32 = (buf[BPB_FATSZ32] + (buf[BPB_FATSZ32+1] << 8)) | + (buf[BPB_FATSZ32+2] << 16) | (buf[BPB_FATSZ32+3] << 24); + + bpb->last_word = buf[BPB_LAST_WORD] | (buf[BPB_LAST_WORD+1] << 8); + + /* Determine FAT type */ + fatsz = fat_get_fatsize(bpb); + + if(bpb->bpb_totsec16 != 0) + totsec = bpb->bpb_totsec16; + else + totsec = bpb->bpb_totsec32; + + rootdirsectors = fat_num_rootdir_sectors(bpb); + datasec = totsec - (bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz + + rootdirsectors); + countofclusters = datasec / bpb->bpb_secperclus; + + if(countofclusters < 4085) + { + bpb->fat_type = FATTYPE_FAT12; + } + else + { + if(countofclusters < 65525) + { + bpb->fat_type = FATTYPE_FAT16; + } + else + { + bpb->fat_type = FATTYPE_FAT32; + } + } + + if(fat_bpb_is_sane(bpb) < 0) + { + fprintf(stderr, "fat_get_bpb() - BPB is not sane\n"); + return -1; + } + + return 0; +} + +int fat_bpb_is_sane(struct bpb *bpb) +{ + if(bpb->fat_type == FATTYPE_FAT32) + { + fprintf(stderr, "fat_bpb_is_sane() - Error: FAT32 not supported\n"); + return -1; + } + + if(bpb->bpb_bytspersec != 512) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: sector size is not 512 (%i)\n", + bpb->bpb_bytspersec); + } + if(bpb->bpb_secperclus * bpb->bpb_bytspersec > 32768) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: cluster size is larger than 32K " + "(%i * %i = %i)\n", + bpb->bpb_bytspersec, bpb->bpb_secperclus, + bpb->bpb_bytspersec * bpb->bpb_secperclus); + } + if(bpb->bpb_rsvdseccnt != 1) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: Reserved sectors is not 1 (%i)\n", + bpb->bpb_rsvdseccnt); + } + if(bpb->bpb_numfats != 2) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: NumFATS is not 2 (%i)\n", + bpb->bpb_numfats); + } + if(bpb->bpb_rootentcnt != 512) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: RootEntCnt is not 512 (%i)\n", + bpb->bpb_rootentcnt); + } + if(bpb->bpb_totsec16 < 200) + { + if(bpb->bpb_totsec16 == 0) + { + fprintf(stderr, "fat_bpb_is_sane() - Error: TotSec16 is 0\n"); + return -1; + } + else + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: TotSec16 " + "is quite small (%i)\n", + bpb->bpb_totsec16); + } + } + if(bpb->bpb_media != 0xf0 && bpb->bpb_media < 0xf8) + { + fprintf(stderr, + "fat_bpb_is_sane() - Warning: Non-standard " + "media type (0x%02x)\n", + bpb->bpb_media); + } + if(bpb->last_word != 0xaa55) + { + fprintf(stderr, "fat_bpb_is_sane() - Error: Last word is not " + "0xaa55 (0x%04x)\n", bpb->last_word); + return -1; + } + return 0; +} + +int fat_create_fat(struct bpb* bpb) +{ + unsigned char *sec; + int i; + int secnum = 0; + int fatsz; + + if(fat_bpb_is_sane(bpb) < 0) + { + fprintf(stderr, "fat_create_fat() - BPB is not sane\n"); + return -1; + } + + if(bpb->bpb_fatsz16 != 0) + fatsz = bpb->bpb_fatsz16; + else + fatsz = bpb->bpb_fatsz32; + + sec = fat_cache_fat_sector(bpb, secnum); + if(!sec) + { + fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector" + " (%d)\n", i); + return -1; + } + + fat_cache_dirty[secnum] = 1; + + /* First entry should have the media type in the + low byte and the rest of the bits set to 1. + The second should be the EOC mark. */ + memset(sec, 0, BLOCK_SIZE); + sec[0] = bpb->bpb_media; + if(bpb->fat_type == FATTYPE_FAT12) + { + sec[1] = 0xff; + sec[2] = 0xff; + } + if(bpb->fat_type == FATTYPE_FAT16) + { + sec[0] = bpb->bpb_media; + sec[1] = 0xff; + sec[2] = 0xff; + sec[3] = 0xff; + } + secnum++; + + for(i = 0; i < fatsz - 1;i++) + { + sec = fat_cache_fat_sector(bpb, secnum); + if(!sec) + { + fprintf(stderr, "fat_create_fat() - Couldn't cache fat sector" + " (%d)\n", i); + return -1; + } + fat_cache_dirty[secnum] = 1; + secnum++; + memset(sec, 0, BLOCK_SIZE); + } + + if(fat_flush_fat(bpb) < 0) + { + fprintf(stderr, "fat_create_fat() - Couldn't flush fat\n"); + return -1; + } + return 0; +} + +int fat_dbg_read_block(char *name, unsigned char *buf) +{ + FILE *f; + + f = fopen(name, "rb"); + if(f) + { + if(fread(buf, 1, 512, f) != 512) + { + fprintf(stderr, "Could not read file \"%s\"\n", name); + fclose(f); + return -1; + } + /* Now write the sector to disk */ + write_block(buf, 0); + fclose(f); + } + else + { + fprintf(stderr, "Could not open file \"%s\"\n", name); + return -1; + } + return 0; +} + +unsigned char *fat_cache_fat_sector(struct bpb *bpb, int secnum) +{ + unsigned char *sec; + + sec = fat_cache[secnum]; + /* Load the sector if it is not cached */ + if(!sec) + { + sec = malloc(bpb->bpb_bytspersec); + if(!sec) + { + fprintf(stderr, "fat_cache_fat_sector() - Out of memory\n"); + return NULL; + } + if(read_block(sec, secnum + bpb->bpb_rsvdseccnt) < 0) + { + fprintf(stderr, "fat_cache_fat_sector() - Could" + " not read sector %d\n", + secnum); + free(sec); + return NULL; + } + fat_cache[secnum] = sec; + } + return sec; +} + +int fat_update_entry(struct bpb *bpb, int entry, unsigned int val) +{ + unsigned char *sec; + unsigned char *sec2; + int fatsz; + int fatoffset; + int thisfatsecnum; + int thisfatentoffset; + unsigned int tmp; + + fatsz = fat_get_fatsize(bpb); + + if(bpb->fat_type == FATTYPE_FAT12) + { + fatoffset = entry + (entry / 2); + } + else + { + if(bpb->fat_type == FATTYPE_FAT16) + fatoffset = entry * 2; + else + fatoffset = entry * 4; + } + thisfatsecnum = fatoffset / bpb->bpb_bytspersec; + thisfatentoffset = fatoffset % bpb->bpb_bytspersec; + + sec = fat_cache_fat_sector(bpb, thisfatsecnum); + /* Load the sector if it is not cached */ + if(!sec) + { + fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n", + thisfatsecnum); + return -1; + } + + fat_cache_dirty[thisfatsecnum] = 1; + + switch(bpb->fat_type) + { + case FATTYPE_FAT12: + if(thisfatentoffset == bpb->bpb_bytspersec - 1) + { + /* This entry spans a sector boundary. Take care */ + sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1); + /* Load the sector if it is not cached */ + if(!sec2) + { + fprintf(stderr, "fat_update_entry() - Could not " + "cache sector %d\n", + thisfatsecnum + 1); + return -1; + } + fat_cache_dirty[thisfatsecnum + 1] = 1; + } + else + { + if(entry & 1) /* Odd entry number? */ + { + tmp = sec[thisfatentoffset] & 0xf0; + sec[thisfatentoffset] = tmp | (val & 0x0f); + sec[thisfatentoffset+1] = (val >> 4) & 0xff; + } + else + { + sec[thisfatentoffset] = val & 0xff; + tmp = sec[thisfatentoffset+1] & 0x0f; + sec[thisfatentoffset+1] = tmp | ((val >> 4) & 0xf0); + } + } + break; + case FATTYPE_FAT16: + *(unsigned short *)(&sec[thisfatentoffset]) = val; + break; + case FATTYPE_FAT32: + tmp = *(unsigned short *)(&sec[thisfatentoffset]) & 0xf000000; + val = tmp | (val & 0x0fffffff); + *(unsigned short *)(&sec[thisfatentoffset]) = val; + break; + } + return 0; +} + +int fat_read_entry(struct bpb *bpb, int entry) +{ + unsigned char *sec; + unsigned char *sec2; + int fatsz; + int fatoffset; + int thisfatsecnum; + int thisfatentoffset; + unsigned int val; + + fatsz = fat_get_fatsize(bpb); + + if(bpb->fat_type == FATTYPE_FAT12) + { + fatoffset = entry + (entry / 2); + } + else + { + if(bpb->fat_type == FATTYPE_FAT16) + fatoffset = entry * 2; + else + fatoffset = entry * 4; + } + thisfatsecnum = fatoffset / bpb->bpb_bytspersec; + thisfatentoffset = fatoffset % bpb->bpb_bytspersec; + + sec = fat_cache_fat_sector(bpb, thisfatsecnum); + /* Load the sector if it is not cached */ + if(!sec) + { + fprintf(stderr, "fat_update_entry() - Could not cache sector %d\n", + thisfatsecnum); + return -1; + } + + switch(bpb->fat_type) + { + case FATTYPE_FAT12: + if(thisfatentoffset == bpb->bpb_bytspersec - 1) + { + /* This entry spans a sector boundary. Take care */ + sec2 = fat_cache_fat_sector(bpb, thisfatsecnum + 1); + /* Load the sector if it is not cached */ + if(!sec2) + { + fprintf(stderr, "fat_update_entry() - Could not " + "cache sector %d\n", + thisfatsecnum + 1); + return -1; + } + } + else + { + if(entry & 1) /* Odd entry number? */ + { + val = (sec[thisfatentoffset] & 0x0f) | + (sec[thisfatentoffset+1] << 4); + } + else + { + val = (sec[thisfatentoffset] & 0xff) | + ((sec[thisfatentoffset+1] & 0x0f) << 8); + } + } + break; + case FATTYPE_FAT16: + val = *(unsigned short *)(&sec[thisfatentoffset]); + break; + case FATTYPE_FAT32: + val = *(unsigned int *)(&sec[thisfatentoffset]); + break; + } + return val; +} + +int fat_flush_fat(struct bpb *bpb) +{ + int i; + int err; + unsigned char *sec; + int fatsz; + unsigned short d, t; + char m; + + fatsz = fat_get_fatsize(bpb); + + for(i = 0;i < 256;i++) + { + if(fat_cache[i] && fat_cache_dirty[i]) + { + printf("Flushing FAT sector %d\n", i); + sec = fat_cache[i]; + err = write_block(sec, i + bpb->bpb_rsvdseccnt); + if(err < 0) + { + fprintf(stderr, "fat_flush_fat() - Couldn't write" + " sector (%d)\n", i + bpb->bpb_rsvdseccnt); + return -1; + } + err = write_block(sec, i + bpb->bpb_rsvdseccnt + fatsz); + if(err < 0) + { + fprintf(stderr, "fat_flush_fat() - Couldn't write" + " sector (%d)\n", i + bpb->bpb_rsvdseccnt + fatsz); + return -1; + } + fat_cache_dirty[i] = 0; + } + } + + fat_getcurrdostime(&d, &t, &m); + return 0; +} + +unsigned int fat_getcurrdostime(unsigned short *dosdate, + unsigned short *dostime, + unsigned char *dostenth) +{ + struct timeb tb; + struct tm *tm; + + ftime(&tb); + tm = localtime(&tb.time); + + *dosdate = ((tm->tm_year - 80) << 9) | + ((tm->tm_mon + 1) << 5) | + (tm->tm_mday); + + *dostime = (tm->tm_hour << 11) | + (tm->tm_min << 5) | + (tm->tm_sec >> 1); + + *dostenth = (tm->tm_sec & 1) * 100 + tb.millitm / 10; + return 0; +} + +int fat_create_root_dir(struct bpb *bpb) +{ + unsigned char buf[BLOCK_SIZE]; + int fatsz; + int sec; + int res; + int i; + unsigned short dosdate; + unsigned short dostime; + unsigned char dostenth; + int num_root_sectors; + + fatsz = fat_get_fatsize(bpb); + + sec = bpb->bpb_rsvdseccnt + bpb->bpb_numfats * fatsz; + + memset(buf, 0, sizeof(buf)); + + strncpy(&buf[FATDIR_NAME], bpb->bs_vollab, 11); + buf[FATDIR_ATTR] = FAT_ATTR_VOLUME_ID; + buf[FATDIR_NTRES] = 0; + + fat_getcurrdostime(&dosdate, &dostime, &dostenth); + buf[FATDIR_WRTDATE] = dosdate & 0xff; + buf[FATDIR_WRTDATE+1] = dosdate >> 8; + buf[FATDIR_WRTTIME] = dostime & 0xff; + buf[FATDIR_WRTTIME+1] = dostime >> 8; + + printf("Writing rootdir to sector %d...\n", sec); + + res = write_block(buf, sec); + if(res < 0) + { + fprintf(stderr, "fat_create_root_dir() - Couldn't write sector (%d)\n", + sec); + return -1; + } + + printf("Clearing the rest of the root dir.\n"); + sec++; + num_root_sectors = bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec; + memset(buf, 0, BLOCK_SIZE); + + for(i = 1;i < num_root_sectors;i++) + { + if(write_block(buf, sec++) < 0) + { + fprintf(stderr, "fat_create_root_dir() - " + " Couldn't write sector (%d)\n", sec); + return -1; + } + } + + return 0; +} + +int fat_get_next_cluster(struct bpb *bpb, unsigned int cluster) +{ + int next_cluster = fat_read_entry(bpb, cluster); + + if(fat_last_cluster_in_chain(bpb, next_cluster)) + return 0; + else + return next_cluster; +} + +int fat_add_dir_entry(struct bpb *bpb, unsigned int currdir, + struct fat_direntry *de) +{ + unsigned char buf[BLOCK_SIZE]; + unsigned char *eptr; + int i; + int err; + unsigned int sec; + unsigned int sec_cnt; + int need_to_update_last_empty_marker = 0; + int is_rootdir = (currdir == 0); + int done = 0; + unsigned char firstbyte; + + if(is_rootdir) + { + sec = fat_get_rootdir_sector(bpb); + } + else + { + sec = fat_first_sector_of_cluster(bpb, currdir); + } + + sec_cnt = 0; + + while(!done) + { + /* The root dir has a fixed size */ + if(is_rootdir) + { + if(sec_cnt >= bpb->bpb_rootentcnt * 32 / bpb->bpb_bytspersec) + { + /* We have reached the last sector of the root dir */ + if(need_to_update_last_empty_marker) + { + /* Since the directory is full, there is no room for + a marker, so we just exit */ + return 0; + } + else + { + fprintf(stderr, "fat_add_dir_entry() -" + " Root dir is full\n"); + return -1; + } + } + } + else + { + if(sec_cnt >= bpb->bpb_secperclus) + { + /* We have reached the end of this cluster */ + printf("Moving to the next cluster..."); + currdir = fat_get_next_cluster(bpb, currdir); + printf("new cluster is %d\n", currdir); + + if(!currdir) + { + /* This was the last in the chain, + we have to allocate a new cluster */ + /* TODO */ + } + } + } + + printf("Reading sector %d...\n", sec); + /* Read the next sector in the current dir */ + err = read_block(buf, sec); + if(err < 0) + { + fprintf(stderr, "fat_add_dir_entry() - Couldn't read dir sector" + " (error code %i)\n", err); + return -1; + } + + if(need_to_update_last_empty_marker) + { + /* All we need to do is to set the first entry to 0 */ + printf("Clearing the first entry in sector %d\n", sec); + buf[0] = 0; + done = 1; + } + else + { + /* Look for a free slot */ + for(i = 0;i < BLOCK_SIZE;i+=32) + { + firstbyte = buf[i]; + if(firstbyte == 0xe5 || firstbyte == 0) + { + printf("Found free slot at entry %d in sector %d\n", + i/32, sec); + eptr = &buf[i]; + memset(eptr, 0, 32); + strncpy(&eptr[FATDIR_NAME], de->name, 11); + eptr[FATDIR_ATTR] = de->attr; + eptr[FATDIR_NTRES] = 0; + + eptr[FATDIR_CRTTIMETENTH] = de->crttimetenth; + eptr[FATDIR_CRTDATE] = de->crtdate & 0xff; + eptr[FATDIR_CRTDATE+1] = de->crtdate >> 8; + eptr[FATDIR_CRTTIME] = de->crttime & 0xff; + eptr[FATDIR_CRTTIME+1] = de->crttime >> 8; + + eptr[FATDIR_WRTDATE] = de->wrtdate & 0xff; + eptr[FATDIR_WRTDATE+1] = de->wrtdate >> 8; + eptr[FATDIR_WRTTIME] = de->wrttime & 0xff; + eptr[FATDIR_WRTTIME+1] = de->wrttime >> 8; + + eptr[FATDIR_FILESIZE] = de->filesize & 0xff; + eptr[FATDIR_FILESIZE+1] = (de->filesize >> 8) & 0xff; + eptr[FATDIR_FILESIZE+2] = (de->filesize >> 16) & 0xff; + eptr[FATDIR_FILESIZE+3] = (de->filesize >> 24) & 0xff; + + /* Advance the last_empty_entry marker */ + if(firstbyte == 0) + { + i += 32; + if(i < BLOCK_SIZE) + { + buf[i] = 0; + /* We are done */ + done = 1; + } + else + { + /* We must fill in the first entry + in the next sector */ + need_to_update_last_empty_marker = 1; + } + } + + err = write_block(buf, sec); + if(err < 0) + { + fprintf(stderr, "fat_add_dir_entry() - " + " Couldn't write dir" + " sector (error code %i)\n", err); + return -1; + } + break; + } + } + } + sec++; + sec_cnt++; + } + + return 0; +} + +unsigned char fat_char2dos(unsigned char c) +{ + switch(c) + { + case 0xe5: /* Special kanji character */ + c = 0x05; + break; + case 0x22: + case 0x2a: + case 0x2b: + case 0x2c: + case 0x2e: + case 0x3a: + case 0x3b: + case 0x3c: + case 0x3d: + case 0x3e: + case 0x3f: + case 0x5b: + case 0x5c: + case 0x5d: + case 0x7c: + /* Illegal name */ + c = 0; + break; + + default: + if(c < 0x20) + { + /* Illegal name */ + c = 0; + } + break; + } + return c; +} + +int fat_create_dos_name(unsigned char *name, unsigned char *newname) +{ + unsigned char n[12]; + unsigned char c; + int i; + char *ext; + + if(strlen(name) > 12) + { + return -1; + } + + strcpy(n, name); + + ext = strchr(n, '.'); + if(ext) + { + *ext++ = 0; + } + + /* The file name is either empty, or there was only an extension. + In either case it is illegal. */ + if(n[0] == 0) + { + return -1; + } + + /* Name part */ + for(i = 0;n[i] && (i < 8);i++) + { + c = fat_char2dos(n[i]); + if(c) + { + newname[i] = toupper(c); + } + } + while(i < 8) + { + newname[i++] = ' '; + } + + /* Extension part */ + for(i = 0;ext && ext[i] && (i < 3);i++) + { + c = fat_char2dos(ext[i]); + if(c) + { + newname[8+i] = toupper(c); + } + } + while(i < 3) + { + newname[8+i++] = ' '; + } + return 0; +} + +int fat_create_dir(struct bpb *bpb, unsigned int currdir, char *name) +{ + struct fat_direntry de; + int err; + + printf("fat_create_file()\n"); + memset(&de, 0, sizeof(struct fat_direntry)); + if(fat_create_dos_name(name, de.name) < 0) + { + fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name); + return -1; + } + + fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth); + de.wrtdate = de.crtdate; + de.wrttime = de.crttime; + de.filesize = 0; + de.attr = FAT_ATTR_DIRECTORY; + + err = fat_add_dir_entry(bpb, currdir, &de); + return 0; +} + +int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name) +{ + struct fat_direntry de; + int err; + + printf("fat_create_file()\n"); + memset(&de, 0, sizeof(struct fat_direntry)); + if(fat_create_dos_name(name, de.name) < 0) + { + fprintf(stderr, "fat_create_file() - Illegal file name (%s)\n", name); + return -1; + } + fat_getcurrdostime(&de.crtdate, &de.crttime, &de.crttimetenth); + de.wrtdate = de.crtdate; + de.wrttime = de.crttime; + de.filesize = 0; + + err = fat_add_dir_entry(bpb, currdir, &de); + return err; +} + +void fat_fill_direntry(struct fat_direntry *de, char *buf) +{ + memset(de, 0, sizeof(struct fat_direntry)); + + strncpy(de->name, &buf[FATDIR_NAME], 11); + de->attr = buf[FATDIR_ATTR]; + de->crttimetenth = buf[FATDIR_CRTTIMETENTH]; + de->crtdate = buf[FATDIR_CRTDATE] | (buf[FATDIR_CRTDATE+1] << 8); + de->crttime = buf[FATDIR_CRTTIME] | (buf[FATDIR_CRTTIME+1] << 8); + de->wrtdate = buf[FATDIR_WRTDATE] | (buf[FATDIR_WRTDATE+1] << 8); + de->wrttime = buf[FATDIR_WRTTIME] | (buf[FATDIR_WRTTIME+1] << 8); + + de->filesize = buf[FATDIR_FILESIZE] | + (buf[FATDIR_FILESIZE+1] << 8) | + (buf[FATDIR_FILESIZE+2] << 16) | + (buf[FATDIR_FILESIZE+3] << 24); +} + +int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir) +{ + int is_rootdir = (currdir == 0); + unsigned int sec; + int err; + + if(is_rootdir) + { + sec = fat_get_rootdir_sector(bpb); + } + else + { + sec = fat_first_sector_of_cluster(bpb, currdir); + } + + /* Read the first sector in the current dir */ + err = read_block(ent->cached_buf, sec); + if(err < 0) + { + fprintf(stderr, "fat_getfirst() - Couldn't read dir sector" + " (error code %i)\n", err); + return -1; + } + + ent->entry = 0; + ent->cached_sec = sec; + ent->num_sec = 0; + return 0; +} + +int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, + struct fat_direntry *entry) +{ + int done = 0; + int i; + int err; + unsigned char firstbyte; + + while(!done) + { + /* Look for a free slot */ + for(i = ent->entry;i < BLOCK_SIZE/32;i++) + { + firstbyte = ent->cached_buf[i*32]; + if(firstbyte == 0xe5) + { + continue; + } + + if(firstbyte == 0) + { + return -1; + } + + fat_fill_direntry(entry, &ent->cached_buf[i*32]); + done = 1; + break; + } + + /* Next sector? */ + if(i >= BLOCK_SIZE/32) + { + ent->num_sec++; + ent->cached_sec++; + + /* Do we need to advance one cluster? */ + if(ent->num_sec >= bpb->bpb_secperclus) + { + ent->num_sec = 0; + ent->cached_sec = fat_get_next_cluster( + bpb, fat_sec2cluster(bpb, ent->cached_sec)); + if(!ent->cached_sec) + { + printf("End of cluster chain.\n"); + return -1; + } + } + + /* Read the next sector */ + err = read_block(ent->cached_buf, ent->cached_sec); + if(err < 0) + { + fprintf(stderr, "fat_getnext() - Couldn't read dir sector" + " (error code %i)\n", err); + return -1; + } + + i = 0; + } + else + { + i++; + } + ent->entry = i; + } + return 0; +} diff --git a/firmware/fat.h b/firmware/fat.h new file mode 100644 index 0000000000..f1dc8dc5a0 --- /dev/null +++ b/firmware/fat.h @@ -0,0 +1,154 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Linus Nielsen Feltzing + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef FAT_H +#define FAT_H + +#define FATTYPE_FAT12 0 +#define FATTYPE_FAT16 1 +#define FATTYPE_FAT32 2 + +#define BS_JMPBOOT 0 +#define BS_OEMNAME 3 +#define BPB_BYTSPERSEC 11 +#define BPB_SECPERCLUS 13 +#define BPB_RSVDSECCNT 14 +#define BPB_NUMFATS 16 +#define BPB_ROOTENTCNT 17 +#define BPB_TOTSEC16 19 +#define BPB_MEDIA 21 +#define BPB_FATSZ16 22 +#define BPB_SECPERTRK 24 +#define BPB_NUMHEADS 26 +#define BPB_HIDDSEC 28 +#define BPB_TOTSEC32 32 + +#define BS_DRVNUM 36 +#define BS_RESERVED1 37 +#define BS_BOOTSIG 38 +#define BS_VOLID 39 +#define BS_VOLLAB 43 +#define BS_FILSYSTYPE 54 + +#define BPB_FATSZ32 36 + +#define BPB_LAST_WORD 510 + +#define MIN(a,b) (((a) < (b))?(a):(b))) + +struct bpb +{ + char bs_oemname[9]; /* OEM string, ending with \0 */ + int bpb_bytspersec; /* Bytes per sectory, typically 512 */ + int bpb_secperclus; /* Sectors per cluster */ + int bpb_rsvdseccnt; /* Number of reserved sectors */ + int bpb_numfats; /* Number of FAT structures, typically 2 */ + int bpb_rootentcnt; /* Number of dir entries in the root */ + int bpb_totsec16; /* Number of sectors on the volume (old 16-bit) */ + int bpb_media; /* Media type (typically 0xf0 or 0xf8) */ + int bpb_fatsz16; /* Number of used sectors per FAT structure */ + int bpb_secpertrk; /* Number of sectors per track */ + int bpb_numheads; /* Number of heads */ + int bpb_hiddsec; /* Hidden sectors before the volume */ + unsigned int bpb_totsec32; /* Number of sectors on the volume + (new 32-bit) */ + /**** FAT12/16 specific *****/ + int bs_drvnum; /* Drive number */ + int bs_bootsig; /* Is 0x29 if the following 3 fields are valid */ + unsigned int bs_volid; /* Volume ID */ + char bs_vollab[12]; /* Volume label, 11 chars plus \0 */ + char bs_filsystype[9]; /* File system type, 8 chars plus \0 */ + + /**** FAT32 specific *****/ + int bpb_fatsz32; + + int last_word; /* Must be 0xaa55 */ + + int fat_type; /* What type of FAT is this? */ +}; + +#define FAT_ATTR_READ_ONLY 0x01 +#define FAT_ATTR_HIDDEN 0x02 +#define FAT_ATTR_SYSTEM 0x04 +#define FAT_ATTR_VOLUME_ID 0x08 +#define FAT_ATTR_DIRECTORY 0x10 +#define FAT_ATTR_ARCHIVE 0x20 +#define FAT_ATTR_LONG_NAME (FAT_ATTR_READ_ONLY | FAT_ATTR_HIDDEN | \ + FAT_ATTR_SYSTEM | FAT_ATTR_VOLUME_ID) + + +#define FATDIR_NAME 0 +#define FATDIR_ATTR 11 +#define FATDIR_NTRES 12 +#define FATDIR_CRTTIMETENTH 13 +#define FATDIR_CRTTIME 14 +#define FATDIR_CRTDATE 16 +#define FATDIR_LSTACCDATE 18 +#define FATDIR_FSTCLUSHI 20 +#define FATDIR_WRTTIME 22 +#define FATDIR_WRTDATE 24 +#define FATDIR_FSTCLUSLO 26 +#define FATDIR_FILESIZE 28 + +struct fat_direntry +{ + unsigned char name[12]; /* Name plus \0 */ + unsigned short attr; /* Attributes */ + unsigned char crttimetenth; /* Millisecond creation + time stamp (0-199) */ + unsigned short crttime; /* Creation time */ + unsigned short crtdate; /* Creation date */ + unsigned short lstaccdate; /* Last access date */ + unsigned short fstclushi; /* High word of first cluster + (0 for FAT12/16) */ + unsigned short wrttime; /* Last write time */ + unsigned short wrtdate; /* Last write date */ + unsigned short fstcluslo; /* Low word of first cluster */ + unsigned int filesize; /* File size in bytes */ +}; + +struct fat_context +{ + unsigned int curr_dir_sec; /* Current directory sector */ + +}; + +struct disk_info +{ + int num_sectors; + int sec_per_track; + int num_heads; + unsigned int hidden_sectors; +}; + +struct fat_dirent +{ + int entry; + unsigned int cached_sec; + unsigned int num_sec; + char cached_buf[BLOCK_SIZE]; +}; + +int fat_format(struct disk_info *di, char *vol_name); +int fat_create_file(struct bpb *bpb, unsigned int currdir, char *name); +int fat_opendir(struct bpb *bpb, struct fat_dirent *ent, unsigned int currdir); +int fat_getnext(struct bpb *bpb, struct fat_dirent *ent, + struct fat_direntry *entry); + +#endif diff --git a/firmware/key.h b/firmware/key.h new file mode 100644 index 0000000000..13d41dbf1e --- /dev/null +++ b/firmware/key.h @@ -0,0 +1,44 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __key_h__ +#define __key_h__ + +#include +#include + +#define key_released(key) \ + (key_released_##key ()) +#define key_pressed(key) \ + (!(key_released_##key ())) + +static inline int key_released_ON (void) + { return (QI(PADR+1)&(1<<5)); } +static inline int key_released_STOP (void) + { return (QI(PADR+0)&(1<<3)); } +static inline int key_released_MINUS (void) + { return (QI(PCDR+0)&(1<<0)); } +static inline int key_released_MENU (void) + { return (QI(PCDR+0)&(1<<1)); } +static inline int key_released_PLUS (void) + { return (QI(PCDR+0)&(1<<2)); } +static inline int key_released_PLAY (void) + { return (QI(PCDR+0)&(1<<3)); } + +#endif diff --git a/firmware/lcd.c b/firmware/lcd.c new file mode 100644 index 0000000000..5563bbe881 --- /dev/null +++ b/firmware/lcd.c @@ -0,0 +1,135 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include "lcd.h" + +void lcd_data (int data) + { lcd_byte (data,1); } + +void lcd_instruction (int instruction) + { lcd_byte (instruction,0); } + +void lcd_zero (int length) + { length *= 8; while (--length >= 0) lcd_data (0); } + +void lcd_fill (int data,int length) + { length *= 8; while (--length >= 0) lcd_data (data); } + +void lcd_copy (void *data,int count) + { while (--count >= 0) lcd_data (*((char *)data)++); } + + +#ifdef JBP +# ifndef JBP_OLD + +static char const lcd_ascii[] = + { +/*****************************************************************************************/ +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ +/* ************************************************************************************/ +/* 0x */ 0x00,0x01,0x02,0x03,0x00,0x00,0x00,0x00,0x04,0x05,0x00,0x00,0x00,0x00,0x00,0x00, +/* 1x */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 2x */ 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F, +/* 3x */ 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F, +/* 4x */ 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F, +/* 5x */ 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0x5F, +/* 6x */ 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F, +/* 7x */ 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x20,0x20,0x20,0x20,0x20, +/* 8x */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* 9x */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* Ax */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* Bx */ 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, +/* Cx */ 0x41,0x41,0x41,0x41,0x41,0x41,0x20,0x43,0x45,0x45,0x45,0x45,0x49,0x49,0x49,0x49, +/* Dx */ 0x44,0x4E,0x4F,0x4F,0x4F,0x4F,0x4F,0x20,0x20,0x55,0x55,0x55,0x55,0x59,0x20,0x20, +/* Ex */ 0x61,0x61,0x61,0x61,0x61,0x61,0x20,0x63,0x65,0x65,0x65,0x65,0x69,0x69,0x69,0x69, +/* Fx */ 0x64,0x6E,0x6F,0x6F,0x6F,0x6F,0x6F,0x20,0x20,0x75,0x75,0x75,0x75,0x79,0x79,0x79 +/******/ + }; + +# else + +static char const lcd_ascii[] = + { +/*****************************************************************************************/ +/* x0 x1 x2 x3 x4 x5 x6 x7 x8 x9 xA xB xC xD xE xF */ +/* ************************************************************************************/ +/* 0x */ 0x00,0x01,0x02,0x03,0x00,0x00,0x00,0x00,0x85,0x89,0x00,0x00,0x00,0x00,0x00,0x00, +/* 1x */ 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, +/* 2x */ 0x24,0x25,0x26,0x37,0x06,0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33, +/* 3x */ 0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x3E,0x3F,0x40,0x41,0x42,0x43, +/* 4x */ 0x44,0x45,0x46,0x47,0x48,0x49,0x4A,0x4B,0x4C,0x4D,0x4E,0x4F,0x50,0x51,0x52,0x53, +/* 5x */ 0x54,0x55,0x56,0x57,0x58,0x59,0x5A,0x5B,0x5C,0x5D,0x5E,0xA9,0x33,0xCE,0x00,0x15, +/* 6x */ 0x00,0x65,0x66,0x67,0x68,0x69,0x6A,0x6B,0x6C,0x6D,0x6E,0x6F,0x70,0x71,0x72,0x73, +/* 7x */ 0x74,0x75,0x76,0x77,0x78,0x79,0x7A,0x7B,0x7C,0x7D,0x7E,0x24,0x24,0x24,0x24,0x24, +/* 8x */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, +/* 9x */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, +/* Ax */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, +/* Bx */ 0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24,0x24, +/* Cx */ 0x45,0x45,0x45,0x45,0x45,0x45,0x24,0x47,0x49,0x49,0x49,0x49,0x4D,0x4D,0x4D,0x4D, +/* Dx */ 0x48,0x52,0x53,0x53,0x53,0x53,0x53,0x24,0x24,0x59,0x59,0x59,0x59,0x5D,0x24,0x24, +/* Ex */ 0x65,0x65,0x65,0x65,0x65,0x65,0x24,0x67,0x69,0x69,0x69,0x69,0x6D,0x6D,0x6D,0x6D, +/* Fx */ 0x73,0x72,0x73,0x73,0x73,0x73,0x73,0x24,0x24,0x79,0x79,0x79,0x79,0x7D,0x24,0x7D +/******/ + }; + +# endif + +void lcd_puts (char const *string) + { + while (*string) + lcd_data (LCD_ASCII(*string++)); + } + +void lcd_putns (char const *string,int n) + { + while (n--) + lcd_data (LCD_ASCII(*string++)); + } + +void lcd_putc (int character) + { + lcd_data (LCD_ASCII(character)); + } + +void lcd_pattern (int which,char const *pattern,int count) + { + lcd_instruction (LCD_PRAM|which); + lcd_copy ((void *)pattern,count); + } + +#else +# error "JBR : FIX ME" +#endif + +void lcd_puthex (unsigned int value,int digits) + { + switch (digits) + { + case 8: + lcd_puthex (value >> 16,4); + case 4: + lcd_puthex (value >> 8,2); + case 2: + lcd_puthex (value >> 4,1); + case 1: + value &= 15; + lcd_putc (value+((value < 10) ? '0' : ('A'-10))); + } + } + diff --git a/firmware/lcd.h b/firmware/lcd.h new file mode 100644 index 0000000000..03c459c303 --- /dev/null +++ b/firmware/lcd.h @@ -0,0 +1,263 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __LCD_H__ +#define __LCD_H__ + +#include +#include + +#define LCDR (PBDR+1) + +/* PA14 : /LCD-BL --- backlight */ +#define LCD_BL (14-8) + +#ifdef JBP /* JukeBox MP3 Player - AJB6K, AJBS20 */ +# define LCD_DS +1 // PB0 = 1 --- 0001 --- LCD-DS +# define LCD_CS +2 // PB1 = 1 --- 0010 --- /LCD-CS +# define LCD_SD +4 // PB2 = 1 --- 0100 --- LCD-SD +# define LCD_SC +8 // PB3 = 1 --- 1000 --- LCD-SC +# ifndef JBP_OLD +# define LCD_CONTRAST_SET ((char)0x50) +# define LCD_CRAM ((char)0x80) /* Characters */ +# define LCD_PRAM ((char)0xC0) /* Patterns */ +# define LCD_IRAM ((char)0x40) /* Icons */ +# else +# define LCD_CONTRAST_SET ((char)0xA8) +# define LCD_CRAM ((char)0xB0) /* Characters */ +# define LCD_PRAM ((char)0x80) /* Patterns */ +# define LCD_IRAM ((char)0xE0) /* Icons */ +# endif +# define LCD_ASCII(c) (lcd_ascii[(c)&255]) +# define LCD_CURSOR(x,y) ((char)(LCD_CRAM+((y)*16+(x)))) +# define LCD_ICON(i) ((char)(LCD_IRAM+i)) +# define LCD_ICON_BATTERY 0 +# define LCD_BATTERY_FRAME 0x02 +# define LCD_BATTERY_BAR1 0x08 +# define LCD_BATTERY_BAR2 0x04 +# define LCD_BATTERY_BAR3 0x10 +# define LCD_ICON_USB 2 +# define LCD_USB_LOGO 0xFF +# define LCD_ICON_PLAY 3 +# define LCD_PLAY_ICON 0xFF +# define LCD_ICON_RECORD 4 +# define LCD_RECORD_ICON 0x10 +# define LCD_ICON_STOP 5 +# define LCD_STOP_ICON 0x0F +# define LCD_ICON_AUDIO 5 +# define LCD_AUDIO_ICON 0xF0 +# define LCD_ICON_REVERSE 6 +# define LCD_REVERSE_ICON 0xFF +# define LCD_ICON_SINGLE 7 +# define LCD_SINGLE_ICON 0xFF +# define LCD_ICON_VOLUME0 9 +# define LCD_VOLUME_ICON 0x04 +# define LCD_VOLUME_BAR1 0x02 +# define LCD_VOLUME_BAR2 0x01 +# define LCD_ICON_VOLUME1 10 +# define LCD_VOLUME_BAR3 0x08 +# define LCD_VOLUME_BAR4 0x04 +# define LCD_VOLUME_BAR5 0x01 +# define LCD_ICON_PARAM 10 +# define LCD_PARAM_SYMBOL 0xF0 +#endif + +#ifdef JBR /* JukeBox MP3 Recorder - AJBR --- FIXME */ +# error "JBR : FIX ME" +#endif + + +/* + * About /CS,DS,SC,SD + * ------------------ + * + * LCD on JBP and JBR uses a SPI protocol to receive orders (SDA and SCK lines) + * + * - /CS -> Chip Selection line : + * 0 : LCD chipset is activated. + * - DS -> Data Selection line, latched at the rising edge + * of the 8th serial clock (*) : + * 0 : instruction register, + * 1 : data register; + * - SC -> Serial Clock line (SDA). + * - SD -> Serial Data line (SCK), latched at the rising edge + * of each serial clock (*). + * + * _ _ + * /CS \ / + * \______________________________________________________/ + * _____ ____ ____ ____ ____ ____ ____ ____ ____ _____ + * SD \/ D7 \/ D6 \/ D5 \/ D4 \/ D3 \/ D2 \/ D1 \/ D0 \/ + * _____/\____/\____/\____/\____/\____/\____/\____/\____/\_____ + * + * _____ _ _ _ _ _ _ _ ________ + * SC \ * \ * \ * \ * \ * \ * \ * \ * + * \_/ \_/ \_/ \_/ \_/ \_/ \_/ \_/ + * _ _________________________________________________________ + * DS \/ + * _/\_________________________________________________________ + * + */ + +/* + * The only way to do logical operations in an atomic way + * on SH1 is using : + * + * or.b/and.b/tst.b/xor.b #imm,@(r0,gbr) + * + * but GCC doesn't generate them at all so some assembly + * codes are needed here. + * + * The Global Base Register gbr is expected to be zero + * and r0 is the address of one register in the on-chip + * peripheral module. + * + */ + +static inline void lcd_start (void) + /* + * Enter a LCD session : + * + * QI(LCDR) &= ~(LCD_CS|LCD_DS|LCD_SD|LCD_SC); + */ + { + asm + ("and.b\t%0,@(r0,gbr)" + : + : /* %0 */ "I"(~(LCD_CS|LCD_DS|LCD_SD|LCD_SC)), + /* %1 */ "z"(LCDR)); + } + +static inline void lcd_stop (void) + /* + * Leave a LCD session : + * + * QI(LCDR) |= LCD_CS|LCD_RS|LCD_SD|LCD_SC; + */ + { + asm + ("or.b\t%0,@(r0,gbr)" + : + : /* %0 */ "I"(LCD_CS|LCD_DS|LCD_SD|LCD_SC), + /* %1 */ "z"(LCDR)); + } + +static inline void lcd_byte (int byte,int rs) + /* + * char j = 0x80; + * if (rs) + * do + * { + * QI(LCDR) &= ~(LCD_SC|LCD_SD); + * if (j & byte) + * QI(LCDR) |= LCD_SD; + * QI(LCDR) |= LCD_SC|LCD_DS; + * } + * while ((unsigned char)j >>= 1); + * else + * do + * { + * QI(LCDR) &= ~(LCD_SC|LCD_SD|LCD_DS); + * if (j & byte) + * QI(LCDR) |= LCD_SD; + * QI(LCDR) |= LCD_SC; + * } + * while ((unsigned char)j >>= 1); + */ + { + if (rs > 0) + asm + ("shll8\t%0\n" + "0:\n\t" + "and.b\t%2,@(r0,gbr)\n\t" + "shll\t%0\n\t" + "bf\t1f\n\t" + "or.b\t%3,@(r0,gbr)\n" + "1:\n\t" + "or.b\t%4,@(r0,gbr)\n" + "add\t#-1,%1\n\t" + "cmp/pl\t%1\n\t" + "bt\t0b" + : + : /* %0 */ "r"(((unsigned)byte)<<16), + /* %1 */ "r"(8), + /* %2 */ "I"(~(LCD_SC|LCD_SD)), + /* %3 */ "I"(LCD_SD), + /* %4 */ "I"(LCD_SC|LCD_DS), + /* %5 */ "z"(LCDR)); + else + asm + ("shll8\t%0\n" + "0:\n\t" + "and.b\t%2,@(r0,gbr)\n\t" + "shll\t%0\n\t" + "bf\t1f\n\t" + "or.b\t%3,@(r0,gbr)\n" + "1:\n\t" + "or.b\t%4,@(r0,gbr)\n" + "add\t#-1,%1\n\t" + "cmp/pl\t%1\n\t" + "bt\t0b" + : + : /* %0 */ "r"(((unsigned)byte)<<16), + /* %1 */ "r"(8), + /* %2 */ "I"(~(LCD_SC|LCD_DS|LCD_SD)), + /* %3 */ "I"(LCD_SD), + /* %4 */ "I"(LCD_SC), + /* %5 */ "z"(LCDR)); + } + +extern void lcd_data (int data); +extern void lcd_instruction (int instruction); +extern void lcd_zero (int length); +extern void lcd_fill (int data,int length); +extern void lcd_copy (void *data,int count); + +#ifdef JBP + +extern void lcd_puts (char const *string); +extern void lcd_putns (char const *string,int n); +extern void lcd_putc (int character); +extern void lcd_puthex (unsigned int value,int digits); + +extern void lcd_pattern (int which,char const *pattern,int count); + +static inline void lcd_goto (int x,int y) + { lcd_instruction (LCD_CURSOR(x,y)); } + +#endif + +#ifdef JBR +# error "JBR : FIX ME" +#endif + +/*** BACKLIGHT ***/ + +static inline void lcd_toggle_backlight (void) + { toggle_bit (LCD_BL,PAIOR); } + +static inline void lcd_turn_on_backlight (void) + { set_bit (LCD_BL,PAIOR); } + +static inline void lcd_turn_off_backlight (void) + { clear_bit (LCD_BL,PAIOR); } + +/*** ICONS ***/ + +#endif diff --git a/firmware/led.c b/firmware/led.c new file mode 100644 index 0000000000..e8922e7891 --- /dev/null +++ b/firmware/led.c @@ -0,0 +1,68 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include + +#define turn_on() \ + set_bit (LEDB,PBDR+1) + +#define turn_off() \ + clear_bit (LEDB,PBDR+1) + +#define start_timer() \ + set_bit (2,ITUTSTR) + +#define stop_timer() \ + clear_bit (2,ITUTSTR) + +#define eoi(subinterrupt) \ + clear_bit (subinterrupt,ITUTSR2) + +#define set_volume(volume) \ + HI(ITUGRA2) = volume & 0x7FFF + + +void led_set_volume (unsigned short volume) + { + volume <<= 10; + if (volume == 0) + led_turn_off (); + else if (volume == 0x8000) + led_turn_on (); + else + { + set_volume (volume); + start_timer (); + } + } + +#pragma interrupt +void IMIA2 (void) + { + turn_off (); + eoi (0); + } + +#pragma interrupt +void OVI2 (void) + { + turn_on (); + eoi (2); + } + diff --git a/firmware/led.h b/firmware/led.h new file mode 100644 index 0000000000..0c43a70e74 --- /dev/null +++ b/firmware/led.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __LED_H__ +#define __LED_H__ + +#include +#include + +#define LEDB 6 /* PB6 : red LED */ + +static inline void led_turn_off (void) + { + clear_bit (LEDB,PBDR+1); + clear_bit (2,ITUTSTR); + } + +static inline void led_turn_on (void) + { + set_bit (LEDB,PBDR+1); + set_bit (2,ITUTSTR); + } + +static inline void led_toggle (void) + { + toggle_bit (LEDB,PBDR+1); + } + +extern void led_set_volume (unsigned short volume); +extern void led_setup (void); + +#endif + + diff --git a/firmware/serial.c b/firmware/serial.c new file mode 100644 index 0000000000..1269083aab --- /dev/null +++ b/firmware/serial.c @@ -0,0 +1,82 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include + +#define TDRE 7 /* transmit data register empty */ +#define RDRF 6 /* receive data register full */ +#define ORER 5 /* overrun error */ +#define FER 4 /* frame error */ +#define PER 3 /* parity error */ + +static int serial_byte,serial_flag; + +void serial_putc (char byte) + { + static int i = 0; + while (!(QI(SCISSR1) & (1< ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __SERIAL_H__ +#define __SERIAL_H__ + +#include +#include + +extern void serial_putc (char); +extern void serial_puts (char const *); +extern int serial_getc (void); +extern void serial_setup (int); + +#endif diff --git a/firmware/sh7034.h b/firmware/sh7034.h new file mode 100644 index 0000000000..c33b7a91bf --- /dev/null +++ b/firmware/sh7034.h @@ -0,0 +1,167 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __SH7034_H__ +#define __SH7034_H__ + +#define GBR 0x00000000 + +#define SCISMR0 0x05FFFEC0 +#define SCIBRR0 0x05FFFEC1 +#define SCISCR0 0x05FFFEC2 +#define SCITDR0 0x05FFFEC3 +#define SCISSR0 0x05FFFEC4 +#define SCIRDR0 0x05FFFEC5 +#define SCISMR1 0x05FFFEC8 +#define SCIBRR1 0x05FFFEC9 +#define SCISCR1 0x05FFFECA +#define SCITDR1 0x05FFFECB +#define SCISSR1 0x05FFFECC +#define SCIRDR1 0x05FFFECD + +#define ADDRA 0x05FFFEE0 +#define ADDRAH 0x05FFFEE0 +#define ADDRAL 0x05FFFEE1 +#define ADDRB 0x05FFFEE2 +#define ADDRBH 0x05FFFEE2 +#define ADDRBL 0x05FFFEE3 +#define ADDRC 0x05FFFEE4 +#define ADDRCH 0x05FFFEE4 +#define ADDRCL 0x05FFFEE5 +#define ADDRD 0x05FFFEE6 +#define ADDRDH 0x05FFFEE6 +#define ADDRDL 0x05FFFEE6 +#define ADCSR 0x05FFFEE8 +#define ADCR 0x05FFFEE9 + +#define ITUTSTR 0x05FFFF00 +#define ITUTSNC 0x05FFFF01 +#define ITUTMDR 0x05FFFF02 +#define ITUTFCR 0x05FFFF03 +#define ITUTCR0 0x05FFFF04 +#define ITUTIOR0 0x05FFFF05 +#define ITUTIER0 0x05FFFF06 +#define ITUTSR0 0x05FFFF07 +#define ITUTCNT0 0x05FFFF08 +#define ITUGRA0 0x05FFFF0A +#define ITUGRB0 0x05FFFF0C +#define ITUTCR1 0x05FFFF0E +#define ITUTIOR1 0x05FFFF0F +#define ITUTIER1 0x05FFFF10 +#define ITUTSR1 0x05FFFF11 +#define ITUTCNT1 0x05FFFF12 +#define ITUGRA1 0x05FFFF14 +#define ITUGRB1 0x05FFFF16 +#define ITUTCR2 0x05FFFF18 +#define ITUTIOR2 0x05FFFF19 +#define ITUTIER2 0x05FFFF1A +#define ITUTSR2 0x05FFFF1B +#define ITUTCNT2 0x05FFFF1C +#define ITUGRA2 0x05FFFF1E +#define ITUGRB2 0x05FFFF20 +#define ITUTCR3 0x05FFFF22 +#define ITUTIOR3 0x05FFFF23 +#define ITUTIER3 0x05FFFF24 +#define ITUTSR3 0x05FFFF25 +#define ITUTCNT3 0x05FFFF26 +#define ITUGRA3 0x05FFFF28 +#define ITUGRB3 0x05FFFF2A +#define ITUBRA3 0x05FFFF2C +#define ITUBRB3 0x05FFFF2E +#define ITUTOCR 0x05FFFF31 +#define ITUTCR4 0x05FFFF32 +#define ITUTIOR4 0x05FFFF33 +#define ITUTIER4 0x05FFFF34 +#define ITUTSR4 0x05FFFF35 +#define ITUTCNT4 0x05FFFF36 +#define ITUGRA4 0x05FFFF38 +#define ITUGRB4 0x05FFFF3A +#define ITUBRA4 0x05FFFF3C +#define ITUBRB4 0x05FFFF3E + +#define DMACSAR0 0x05FFFF40 +#define DMACDAR0 0x05FFFF44 +#define DMACOR 0x05FFFF48 +#define DMACTCR0 0x05FFFF4A +#define DMACCHCR0 0x05FFFF4E +#define DMACSAR1 0x05FFFF50 +#define DMACDAR1 0x05FFFF54 +#define DMACTCR1 0x05FFFF5A +#define DMACCHCR1 0x05FFFF5E +#define DMACSAR2 0x05FFFF60 +#define DMACDAR2 0x05FFFF64 +#define DMACTCR2 0x05FFFF6A +#define DMACCHCR2 0x05FFFF6E +#define DMACSAR3 0x05FFFF70 +#define DMACDAR3 0x05FFFF74 +#define DMACTCR3 0x05FFFF7A +#define DMACCHCR3 0x05FFFF7E + +#define INTCIPRAB 0x05FFFF84 +#define INTCIPRA 0x05FFFF84 +#define INTCIPRB 0x05FFFF86 +#define INTCIPRCD 0x05FFFF88 +#define INTCIPRC 0x05FFFF88 +#define INTCIPRD 0x05FFFF8A +#define INTCIPRE 0x05FFFF8C +#define INTCICR 0x05FFFF8E + +#define UBCBAR 0x05FFFF90 +#define UBCBARH 0x05FFFF90 +#define UBCBARL 0x05FFFF92 +#define UBCBAMR 0x05FFFF94 +#define UBCBAMRH 0x05FFFF94 +#define UBCBAMRL 0x05FFFF96 +#define UBCBBR 0x05FFFF98 + +#define BSCBCR 0x05FFFFA0 +#define BSCWCR1 0x05FFFFA2 +#define BSCWCR2 0x05FFFFA4 +#define BSCWCR3 0x05FFFFA6 +#define BSCDCR 0x05FFFFA8 +#define BSCPCR 0x05FFFFAA +#define BSCRCR 0x05FFFFAC +#define BSCRTCSR 0x05FFFFAE +#define BSCRTCNT 0x05FFFFB0 +#define BSCRTCOR 0x05FFFFB2 + +#define WDTTCSR 0x05FFFFB8 +#define WDTTCNT 0x05FFFFB9 +#define WDTRSTCSR 0x05FFFFBB + +#define SBYCR 0x05FFFFBC + +#define PABDR 0x05FFFFC0 +#define PADR 0x05FFFFC0 +#define PBDR 0x05FFFFC2 +#define PABIOR 0x05FFFFC4 +#define PAIOR 0x05FFFFC4 +#define PBIOR 0x05FFFFC6 +#define PACR 0x05FFFFC8 +#define PACR1 0x05FFFFC8 +#define PACR2 0x05FFFFCA +#define PBCR 0x05FFFFCC +#define PBCR1 0x05FFFFCC +#define PBCR2 0x05FFFFCE +#define PCDR 0x05FFFFD1 + +#define CASCR 0x05FFFFEE + + +#endif diff --git a/firmware/start.s b/firmware/start.s new file mode 100644 index 0000000000..fdc86b2de1 --- /dev/null +++ b/firmware/start.s @@ -0,0 +1,41 @@ +!---------------------------------------------------------------------------- +! __________ __ ___. +! Open \______ \ ____ ____ | | _\_ |__ _______ ___ +! Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / +! Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < +! Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ +! \/ \/ \/ \/ \/ +! $Id$ +! +! Copyright (C) 2002 by Björn Stenberg +! +! All files in this archive are subject to the GNU General Public License. +! See the file COPYING in the source tree root for full license agreement. +! +! This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY +! KIND, either express or implied. +!---------------------------------------------------------------------------- +! +! note: sh-1 has a "delay cycle" after every branch where you can +! execute another instruction "for free". + + .file "start.s" + .section .text.start + .extern _main + .extern _vectors + .extern _stack + .global _start + .align 2 + +_start: + mov.l 1f, r1 + mov.l 3f, r3 + mov.l 2f, r15 + jmp @r3 + ldc r1, vbr + nop + +1: .long _vectors +2: .long _stack +3: .long _main + .type _start,@function diff --git a/firmware/system.c b/firmware/system.c new file mode 100644 index 0000000000..8e9c7ff692 --- /dev/null +++ b/firmware/system.c @@ -0,0 +1,432 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#include +#include + +#define default_interrupt(name,number) \ + extern __attribute__((weak,alias("UIE" #number))) void name (void); void UIE##number (void) +#define reserve_interrupt(number) \ + void UIE##number (void) + +extern void reset_pc (void); +extern void reset_sp (void); + +reserve_interrupt ( 0); +reserve_interrupt ( 1); +reserve_interrupt ( 2); +reserve_interrupt ( 3); +default_interrupt (GII, 4); +reserve_interrupt ( 5); +default_interrupt (ISI, 6); +reserve_interrupt ( 7); +reserve_interrupt ( 8); +default_interrupt (CPUAE, 9); +default_interrupt (DMAAE, 10); +default_interrupt (NMI, 11); +default_interrupt (UB, 12); +reserve_interrupt ( 13); +reserve_interrupt ( 14); +reserve_interrupt ( 15); +reserve_interrupt ( 16); // TCB #0 +reserve_interrupt ( 17); // TCB #1 +reserve_interrupt ( 18); // TCB #2 +reserve_interrupt ( 19); // TCB #3 +reserve_interrupt ( 20); // TCB #4 +reserve_interrupt ( 21); // TCB #5 +reserve_interrupt ( 22); // TCB #6 +reserve_interrupt ( 23); // TCB #7 +reserve_interrupt ( 24); // TCB #8 +reserve_interrupt ( 25); // TCB #9 +reserve_interrupt ( 26); // TCB #10 +reserve_interrupt ( 27); // TCB #11 +reserve_interrupt ( 28); // TCB #12 +reserve_interrupt ( 29); // TCB #13 +reserve_interrupt ( 30); // TCB #14 +reserve_interrupt ( 31); // TCB #15 +default_interrupt (TRAPA32, 32); +default_interrupt (TRAPA33, 33); +default_interrupt (TRAPA34, 34); +default_interrupt (TRAPA35, 35); +default_interrupt (TRAPA36, 36); +default_interrupt (TRAPA37, 37); +default_interrupt (TRAPA38, 38); +default_interrupt (TRAPA39, 39); +default_interrupt (TRAPA40, 40); +default_interrupt (TRAPA41, 41); +default_interrupt (TRAPA42, 42); +default_interrupt (TRAPA43, 43); +default_interrupt (TRAPA44, 44); +default_interrupt (TRAPA45, 45); +default_interrupt (TRAPA46, 46); +default_interrupt (TRAPA47, 47); +default_interrupt (TRAPA48, 48); +default_interrupt (TRAPA49, 49); +default_interrupt (TRAPA50, 50); +default_interrupt (TRAPA51, 51); +default_interrupt (TRAPA52, 52); +default_interrupt (TRAPA53, 53); +default_interrupt (TRAPA54, 54); +default_interrupt (TRAPA55, 55); +default_interrupt (TRAPA56, 56); +default_interrupt (TRAPA57, 57); +default_interrupt (TRAPA58, 58); +default_interrupt (TRAPA59, 59); +default_interrupt (TRAPA60, 60); +default_interrupt (TRAPA61, 61); +default_interrupt (TRAPA62, 62); +default_interrupt (TRAPA63, 63); +default_interrupt (IRQ0, 64); +default_interrupt (IRQ1, 65); +default_interrupt (IRQ2, 66); +default_interrupt (IRQ3, 67); +default_interrupt (IRQ4, 68); +default_interrupt (IRQ5, 69); +default_interrupt (IRQ6, 70); +default_interrupt (IRQ7, 71); +default_interrupt (DEI0, 72); +reserve_interrupt ( 73); +default_interrupt (DEI1, 74); +reserve_interrupt ( 75); +default_interrupt (DEI2, 76); +reserve_interrupt ( 77); +default_interrupt (DEI3, 78); +reserve_interrupt ( 79); +default_interrupt (IMIA0, 80); +default_interrupt (IMIB0, 81); +default_interrupt (OVI0, 82); +reserve_interrupt ( 83); +default_interrupt (IMIA1, 84); +default_interrupt (IMIB1, 85); +default_interrupt (OVI1, 86); +reserve_interrupt ( 87); +default_interrupt (IMIA2, 88); +default_interrupt (IMIB2, 89); +default_interrupt (OVI2, 90); +reserve_interrupt ( 91); +default_interrupt (IMIA3, 92); +default_interrupt (IMIB3, 93); +default_interrupt (OVI3, 94); +reserve_interrupt ( 95); +default_interrupt (IMIA4, 96); +default_interrupt (IMIB4, 97); +default_interrupt (OVI4, 98); +reserve_interrupt ( 99); +default_interrupt (REI0, 100); +default_interrupt (RXI0, 101); +default_interrupt (TXI0, 102); +default_interrupt (TEI0, 103); +default_interrupt (REI1, 104); +default_interrupt (RXI1, 105); +default_interrupt (TXI1, 106); +default_interrupt (TEI1, 107); +reserve_interrupt ( 108); +default_interrupt (ADITI, 109); + +void (*vbr[]) (void) __attribute__ ((section (".sram.vbr"))) = + { + /*** 0-1 Power-on Reset ***/ + + reset_pc,reset_sp, + + /*** 2-3 Manual Reset ***/ + + reset_pc,reset_sp, + + /*** 4 General Illegal Instruction ***/ + + GII, + + /*** 5 Reserved ***/ + + UIE5, + + /*** 6 Illegal Slot Instruction ***/ + + ISI, + + /*** 7-8 Reserved ***/ + + UIE7,UIE8, + + /*** 9 CPU Address Error ***/ + + CPUAE, + + /*** 10 DMA Address Error ***/ + + DMAAE, + + /*** 11 NMI ***/ + + NMI, + + /*** 12 User Break ***/ + + UB, + + /*** 13-31 Reserved ***/ + + UIE13,UIE14,UIE15,UIE16,UIE17,UIE18,UIE19,UIE20,UIE21,UIE22,UIE23,UIE24,UIE25,UIE26,UIE27,UIE28,UIE29,UIE30,UIE31, + + /*** 32-63 TRAPA #20...#3F ***/ + + TRAPA32,TRAPA33,TRAPA34,TRAPA35,TRAPA36,TRAPA37,TRAPA38,TRAPA39,TRAPA40,TRAPA41,TRAPA42,TRAPA43,TRAPA44,TRAPA45,TRAPA46,TRAPA47,TRAPA48,TRAPA49,TRAPA50,TRAPA51,TRAPA52,TRAPA53,TRAPA54,TRAPA55,TRAPA56,TRAPA57,TRAPA58,TRAPA59,TRAPA60,TRAPA61,TRAPA62,TRAPA63, + + /*** 64-71 IRQ0-7 ***/ + + IRQ0,IRQ1,IRQ2,IRQ3,IRQ4,IRQ5,IRQ6,IRQ7, + + /*** 72 DMAC0 ***/ + + DEI0, + + /*** 73 Reserved ***/ + + UIE73, + + /*** 74 DMAC1 ***/ + + DEI1, + + /*** 75 Reserved ***/ + + UIE75, + + /*** 76 DMAC2 ***/ + + DEI2, + + /*** 77 Reserved ***/ + + UIE77, + + /*** 78 DMAC3 ***/ + + DEI3, + + /*** 79 Reserved ***/ + + UIE79, + + /*** 80-82 ITU0 ***/ + + IMIA0,IMIB0,OVI0, + + /*** 83 Reserved ***/ + + UIE83, + + /*** 84-86 ITU1 ***/ + + IMIA1,IMIB1,OVI1, + + /*** 87 Reserved ***/ + + UIE87, + + /*** 88-90 ITU2 ***/ + + IMIA2,IMIB2,OVI2, + + /*** 91 Reserved ***/ + + UIE91, + + /*** 92-94 ITU3 ***/ + + IMIA3,IMIB3,OVI3, + + /*** 95 Reserved ***/ + + UIE95, + + /*** 96-98 ITU4 ***/ + + IMIA4,IMIB4,OVI4, + + /*** 99 Reserved ***/ + + UIE99, + + /*** 100-103 SCI0 ***/ + + REI0,RXI0,TXI0,TEI0, + + /*** 104-107 SCI1 ***/ + + REI1,RXI1,TXI1,TEI1, + + /*** 108 Parity Control Unit ***/ + + UIE108, + + /*** 109 AD Converter ***/ + + ADITI + + }; + + +void system_reboot (void) + { + cli (); + + asm volatile ("ldc\t%0,vbr" : : "r"(0)); + + SI(INTCIPRAB) = + SI(INTCIPRCD) = 0; + HI(INTCIPRE) = + HI(INTCICR) = 0; + + asm volatile ("jmp @%0; mov.l @%1,r15" : : "r"(SI(0)),"r"(4)); + } + +void UIE (unsigned int pc) /* Unexpected Interrupt or Exception */ + { + unsigned int i,n; + lcd_stop (); + asm volatile ("sts\tpr,%0" : "=r"(n)); + n = (n - (unsigned)UIE0 - 4)>>2; // get exception or interrupt number + lcd_start (); + lcd_goto (0,0); lcd_puts ("** UIE00 **"); + lcd_goto (0,1); lcd_puts ("AT 00000000"); + lcd_goto (6,0); lcd_puthex (n,2); + lcd_goto (3,1); lcd_puthex (pc,8); /* or pc - 4 !? */ + lcd_stop (); + + while (1) + { + led_toggle (); + + for (i = 0; i < 240000; ++i); + } + } + +asm ( + "_UIE0:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE1:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE2:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE3:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE4:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE5:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE6:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE7:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE8:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE9:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE10:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE11:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE12:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE13:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE14:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE15:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE16:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE17:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE18:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE19:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE20:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE21:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE22:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE23:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE24:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE25:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE26:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE27:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE28:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE29:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE30:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE31:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE32:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE33:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE34:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE35:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE36:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE37:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE38:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE39:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE40:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE41:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE42:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE43:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE44:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE45:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE46:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE47:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE48:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE49:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE50:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE51:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE52:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE53:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE54:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE55:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE56:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE57:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE58:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE59:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE60:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE61:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE62:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE63:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE64:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE65:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE66:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE67:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE68:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE69:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE70:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE71:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE72:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE73:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE74:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE75:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE76:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE77:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE78:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE79:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE80:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE81:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE82:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE83:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE84:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE85:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE86:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE87:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE88:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE89:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE90:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE91:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE92:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE93:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE94:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE95:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE96:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE97:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE98:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE99:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE100:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE101:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE102:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE103:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE104:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE105:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE106:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE107:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE108:\tbsr\t_UIE\n\tmov.l\t@r15+,r4\t\n" + "_UIE109:\tbsr\t_UIE\n\tmov.l\t@r15+,r4"); diff --git a/firmware/system.h b/firmware/system.h new file mode 100644 index 0000000000..bacf90ad66 --- /dev/null +++ b/firmware/system.h @@ -0,0 +1,267 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2002 by Alan Korr + * + * All files in this archive are subject to the GNU General Public License. + * See the file COPYING in the source tree root for full license agreement. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ + +#ifndef __SYSTEM_H__ +#define __SYSTEM_H__ +#include + +#define KB *1024 +#define MB *1024 KB +#define GB *1024 MB + +#define Hz *1 +#define KHz *1000 Hz +#define MHz *1000 KHz + +#define ns *1 +#define us *1000 ns +#define ms *1000 us + +/* + * 11.059,200 MHz => 90.4224537037037037037037037037037... ns + * 12.000,000 MHz => 83.3333333333333333333333333333333... ns + */ + +#define PHI ((int)(12.000000 MHz)) +#define BAUDRATE 9600 + +//#define PHI ((int)(11.059200 MHz)) +//#define BAUDRATE 115200 /* 115200 - 9600 */ + +#define SI(a) \ + (*((volatile int *)a)) /* single integer access - 32-bit */ +#define HI(a) \ + (*((volatile short *)a)) /* half integer access - 16-bit */ +#define QI(a) \ + (*((volatile char *)a)) /* quarter integer access - 8-bit */ + +#define nop \ + asm volatile ("nop") + +#define __set_mask_constant(mask,address) \ + asm \ + ("or.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)(mask)), \ + /* %1 */ "z"(address-GBR)) + +#define __clear_mask_constant(mask,address) \ + asm \ + ("and.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)~(mask)), \ + /* %1 */ "z"(address-GBR)) + +#define __toggle_mask_constant(mask,address) \ + asm \ + ("xor.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)(mask)), \ + /* %1 */ "z"(address-GBR)) + +#define __test_mask_constant(mask,address) \ + ({ \ + int result; \ + asm \ + ("tst.b\t%1,@(r0,gbr)\n\tmovt\t%0" \ + : "=r"(result) \ + : "I"((char)(mask)),"z"(address-GBR)); \ + result; \ + }) + +#define __set_bit_constant(bit,address) \ + asm \ + ("or.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)(1<<(bit))), \ + /* %1 */ "z"(address-GBR)) + +#define __clear_bit_constant(bit,address) \ + asm \ + ("and.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)~(1<<(bit))), \ + /* %1 */ "z"(address-GBR)) + +#define __toggle_bit_constant(bit,address) \ + asm \ + ("xor.b\t%0,@(r0,gbr)" \ + : \ + : /* %0 */ "I"((char)(1<<(bit))), \ + /* %1 */ "z"(address-GBR)) + +#define __test_bit_constant(bit,address) \ + ({ \ + int result; \ + asm \ + ("tst.b\t%1,@(r0,gbr)\n\tmovt\t%0" \ + : "=r"(result) \ + : "I"((char)(1<<(bit))),"z"(address-GBR)); \ + result; \ + }) + +#define __set_mask(mask,address) /* FIXME */ +#define __test_mask(mask,address) 0 /* FIXME */ +#define __clear_mask(mask,address) /* FIXME */ +#define __toggle_mask(mask,address) /* FIXME */ + +#define __set_bit(bit,address) /* FIXME */ +#define __test_bit(bit,address) 0 /* FIXME */ +#define __clear_bit(bit,address) /* FIXME */ +#define __toggle_bit(bit,address) /* FIXME */ + +#define set_mask(mask,address) \ + if (__builtin_constant_p (mask)) \ + __set_mask_constant (mask,address); \ + else \ + __set_mask (mask,address) + +#define clear_mask(mask,address) \ + if (__builtin_constant_p (mask)) \ + __clear_mask_constant (mask,address); \ + else \ + __clear_mask (mask,address) + +#define toggle_mask(mask,address) \ + if (__builtin_constant_p (mask)) \ + __toggle_mask_constant (mask,address); \ + else \ + __toggle_mask (mask,address) + +#define test_mask(mask,address) \ + ( \ + (__builtin_constant_p (mask)) \ + ? (int)__test_mask_constant (mask,address) \ + : (int)__test_mask (mask,address) \ + ) + + +#define set_bit(bit,address) \ + if (__builtin_constant_p (bit)) \ + __set_bit_constant (bit,address); \ + else \ + __set_bit (bit,address) + +#define clear_bit(bit,address) \ + if (__builtin_constant_p (bit)) \ + __clear_bit_constant (bit,address); \ + else \ + __clear_bit (bit,address) + +#define toggle_bit(bit,address) \ + if (__builtin_constant_p (bit)) \ + __toggle_bit_constant (bit,address); \ + else \ + __toggle_bit (bit,address) + +#define test_bit(bit,address) \ + ( \ + (__builtin_constant_p (bit)) \ + ? (int)__test_bit_constant (bit,address) \ + : (int)__test_bit (bit,address) \ + ) + + +extern char __swap_bit[256]; + +#define swap_bit(byte) \ + __swap_bit[byte] + +static inline short swabHI (short value) + /* + result[15..8] = value[ 7..0]; + result[ 7..0] = value[15..8]; + */ + { + short result; + asm volatile ("swap.b\t%1,%0" : "=r"(result) : "r"(value)); + return result; + } + +static inline int swawSI (int value) + /* + result[31..16] = value[15.. 0]; + result[15.. 0] = value[31..16]; + */ + { + int result; + asm volatile ("swap.w\t%1,%0" : "=r"(result) : "r"(value)); + return result; + } + +static inline int swabSI (int value) // should be avoided as much as possible + /* + result[31..24] = value[ 7.. 0]; + result[23..16] = value[15.. 8]; + result[15.. 8] = value[23..16]; + result[ 7.. 0] = value[31..24]; + */ + { + return swabHI(swawSI(swabSI(value))); + } + +/* Test And Set - UNTESTED */ +static inline int tas (volatile int *pointer) + { + int result; + asm volatile ("tas.b\t@%1;movt\t%0" : "=t"(result) : "r"((char *)pointer) : "memory"); + return result; + } + +static inline void sti (void) + { + asm volatile ("ldc\t%0,sr" : : "r"(0<<4)); + } + +static inline void cli (void) + { + asm volatile ("ldc\t%0,sr" : : "r"(15<<4)); + } + +/* Compare And Swap */ +static inline int cas (volatile int *pointer,int requested_value,int new_value) + { + cli(); + if (*pointer == requested_value) + { + *pointer = new_value; + sti (); + return 1; + } + sti (); + return 0; + } + +static inline int cas2 (volatile int *pointer1,volatile int *pointer2,int requested_value1,int requested_value2,int new_value1,int new_value2) + { + cli(); + if (*pointer1 == requested_value1 && *pointer2 == requested_value2) + { + *pointer1 = new_value1; + *pointer2 = new_value2; + sti (); + return 1; + } + sti (); + return 0; + } + +extern void system_reboot (void); + +#endif