f53db11e2189ac5099b12987fe5a4d0f2ef23ff6
[picodrive.git] / Pico / cd / buffering.c
1 // Buffering handling
2 // (c) Copyright 2007, Grazvydas "notaz" Ignotas
3
4 #include "../PicoInt.h"
5
6 //#include <stdlib.h>
7
8 int PicoCDBuffers = 0;
9 static unsigned char *cd_buffer = NULL;
10 static int prev_lba = 0x80000000;
11
12 static int hits, reads;
13
14
15 void PicoCDBufferInit(void)
16 {
17         void *tmp;
18
19         prev_lba = 0x80000000;
20         hits = reads = 0;
21
22         if (PicoCDBuffers <= 1) {
23                 PicoCDBuffers = 0;
24                 return; /* buffering off */
25         }
26
27         /* try alloc'ing until we succeed */
28         while (PicoCDBuffers > 0)
29         {
30                 tmp = realloc(cd_buffer, PicoCDBuffers * 2048);
31                 if (tmp != NULL) break;
32                 PicoCDBuffers >>= 1;
33         }
34
35         if (PicoCDBuffers <= 0) return; /* buffering became off */
36
37         cd_buffer = tmp;
38 }
39
40
41 void PicoCDBufferFree(void)
42 {
43         if (cd_buffer) {
44                 free(cd_buffer);
45                 cd_buffer = NULL;
46         }
47         if (reads)
48                 printf("CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
49 }
50
51
52 /* this is a try to fight slow SD access of GP2X */
53 void PicoCDBufferRead(void *dest, int lba)
54 {
55         int is_bin, offs, read_len, moved = 0;
56         reads++;
57
58         is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN;
59
60         if (PicoCDBuffers <= 0)
61         {
62                 /* no buffering */
63                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
64                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
65                 pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
66                 return;
67         }
68
69         /* hit? */
70         offs = lba - prev_lba;
71         if (offs >= 0 && offs < PicoCDBuffers)
72         {
73                 hits++;
74                 if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
75                 memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
76                 return;
77         }
78
79         if (prev_lba + PicoCDBuffers != lba)
80         {
81                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
82                 dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
83                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
84         }
85
86         dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
87
88         if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
89         {
90                 read_len = prev_lba - lba;
91                 dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
92                 memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
93                 moved = 1;
94         }
95         else
96         {
97                 read_len = PicoCDBuffers;
98         }
99
100         if (PicoMessage != NULL && read_len >= 512)
101         {
102                 PicoMessage("Buffering data...");
103         }
104
105         if (is_bin)
106         {
107                 int i;
108                 for (i = 0; i < read_len; i++)
109                 {
110                         pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
111                         pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
112                 }
113         }
114         else
115         {
116                 pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
117         }
118         memcpy32(dest, (int *) cd_buffer, 2048/4);
119         prev_lba = lba;
120
121         if (moved)
122         {
123                 /* file pointer must point to the same data in file, as would-be data after our buffer */
124                 int where_seek;
125                 lba += PicoCDBuffers;
126                 where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
127                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
128         }
129 }
130