summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBjörn Stenberg <bjorn@haxx.se>2002-03-28 15:09:10 +0000
committerBjörn Stenberg <bjorn@haxx.se>2002-03-28 15:09:10 +0000
commitd9eb5c76032867f2f1f03d591c61c59be799fa7a (patch)
treef0adb17755cc95ddc908842b7d5ff63f5cd4db4e
parentcd0f122071947ea08edea827efe176413de07151 (diff)
downloadrockbox-d9eb5c76032867f2f1f03d591c61c59be799fa7a.zip
rockbox-d9eb5c76032867f2f1f03d591c61c59be799fa7a.tar.gz
rockbox-d9eb5c76032867f2f1f03d591c61c59be799fa7a.tar.bz2
rockbox-d9eb5c76032867f2f1f03d591c61c59be799fa7a.tar.xz
First version
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@60 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--firmware/Makefile47
-rw-r--r--firmware/app.lds23
-rw-r--r--firmware/fat.c1315
-rw-r--r--firmware/fat.h154
-rw-r--r--firmware/key.h44
-rw-r--r--firmware/lcd.c135
-rw-r--r--firmware/lcd.h263
-rw-r--r--firmware/led.c68
-rw-r--r--firmware/led.h50
-rw-r--r--firmware/serial.c82
-rw-r--r--firmware/serial.h31
-rw-r--r--firmware/sh7034.h167
-rw-r--r--firmware/start.s41
-rw-r--r--firmware/system.c432
-rw-r--r--firmware/system.h267
15 files changed, 3119 insertions, 0 deletions
diff --git a/firmware/Makefile b/firmware/Makefile
new file mode 100644
index 0000000..9b38303
--- /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 0000000..03bd1b2
--- /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 0000000..235341f
--- /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 <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/timeb.h>
+
+#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 0000000..f1dc8dc
--- /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 0000000..13d41db
--- /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 <sh7034.h>
+#include <system.h>
+
+#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 0000000..5563bbe
--- /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 0000000..03c459c
--- /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 <sh7034.h>
+#include <system.h>
+
+#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 0000000..e8922e7
--- /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 <led.h>
+
+#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 0000000..0c43a70
--- /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 <sh7034.h>
+#include <system.h>
+
+#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 0000000..1269083
--- /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 <serial.h>
+#include <lcd.h>
+
+#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<<TDRE)));
+ QI(SCITDR1) = byte;
+ clear_bit (TDRE,SCISSR1);
+ lcd_goto ((i++)%11,1); lcd_putc (byte);
+ }
+
+void serial_puts (char const *string)
+ {
+ int byte;
+ while ((byte = *string++))
+ serial_putc (byte);
+ }
+
+int serial_getc( void )
+ {
+ int byte;
+ while (!serial_flag);
+ byte = serial_byte;
+ serial_flag = 0;
+ serial_putc (byte);
+ return byte;
+ }
+
+void serial_setup (int baudrate)
+ {
+ QI(SCISCR1) =
+ QI(SCISSR1) =
+ QI(SCISMR1) = 0;
+ QI(SCIBRR1) = (PHI/(32*baudrate))-1;
+ QI(SCISCR1) = 0x70;
+ }
+
+#pragma interrupt
+void REI1 (void)
+ {
+ clear_bit (FER,SCISSR1);
+ }
+
+#pragma interrupt
+void RXI1 (void)
+ {
+ serial_byte = QI(SCIRDR1);
+ serial_flag = 1;
+ clear_bit (RDRF,SCISSR1);
+ if (serial_byte == '0')
+ lcd_turn_off_backlight ();
+ if (serial_byte == '1')
+ lcd_turn_on_backlight ();
+ }
diff --git a/firmware/serial.h b/firmware/serial.h
new file mode 100644
index 0000000..eac02e4
--- /dev/null
+++ b/firmware/serial.h
@@ -0,0 +1,31 @@
+/***************************************************************************
+ * __________ __ ___.
+ * 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 __SERIAL_H__
+#define __SERIAL_H__
+
+#include <sh7034.h>
+#include <system.h>
+
+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 0000000..c33b7a9
--- /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 0000000..fdc86b2
--- /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 0000000..8e9c7ff
--- /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 <lcd.h>
+#include <led.h>
+
+#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 0000000..bacf90a
--- /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 <sh7034.h>
+
+#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