8420336939f21a2770769e24916e27640f41bc8f
[picodrive.git] / pico / cd / buffering.c
1 /*
2  * Buffering handling
3  * (C) notaz, 2007,2008
4  *
5  * This work is licensed under the terms of MAME license.
6  * See COPYING file in the top-level directory.
7  */
8
9 #include "../pico_int.h"
10 #include "../cd/cue.h"
11
12 int PicoCDBuffers = 0;
13 static unsigned char *cd_buffer = NULL;
14 static int prev_lba = 0x80000000;
15
16 static int hits, reads;
17
18 #undef dprintf
19 #define dprintf(...)
20
21 void PicoCDBufferInit(void)
22 {
23         void *tmp = NULL;
24
25         prev_lba = 0x80000000;
26         hits = reads = 0;
27
28         if (PicoCDBuffers <= 1) {
29                 PicoCDBuffers = 0;
30                 return; /* buffering off */
31         }
32
33         /* try alloc'ing until we succeed */
34         while (PicoCDBuffers > 0)
35         {
36                 tmp = realloc(cd_buffer, PicoCDBuffers * 2048 + 304);
37                 if (tmp != NULL) break;
38                 PicoCDBuffers >>= 1;
39         }
40
41         if (PicoCDBuffers <= 0) return; /* buffering became off */
42
43         cd_buffer = tmp;
44 }
45
46
47 void PicoCDBufferFree(void)
48 {
49         if (cd_buffer) {
50                 free(cd_buffer);
51                 cd_buffer = NULL;
52         }
53         if (reads)
54                 elprintf(EL_STATUS, "CD buffer hits: %i/%i (%i%%)\n", hits, reads, hits * 100 / reads);
55 }
56
57
58 void PicoCDBufferFlush(void)
59 {
60         prev_lba = 0x80000000;
61 }
62
63
64 /* this is was a try to fight slow SD access of GP2X */
65 PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
66 {
67         int is_bin, offs, read_len, moved = 0;
68         reads++;
69
70         is_bin = Pico_mcd->TOC.Tracks[0].ftype == CT_BIN;
71
72         if (PicoCDBuffers <= 0)
73         {
74                 /* no buffering */
75                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
76                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
77                 pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
78                 return;
79         }
80
81         /* hit? */
82         offs = lba - prev_lba;
83         if (offs >= 0 && offs < PicoCDBuffers)
84         {
85                 hits++;
86                 if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
87                 memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
88                 return;
89         }
90
91         if (prev_lba + PicoCDBuffers != lba)
92         {
93                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
94                 dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
95                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
96         }
97
98         dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
99
100         if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
101         {
102                 read_len = prev_lba - lba;
103                 dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
104                 memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
105                 moved = 1;
106         }
107         else
108         {
109                 read_len = PicoCDBuffers;
110         }
111
112         if (PicoMessage != NULL && read_len >= 512)
113         {
114                 PicoMessage("Buffering data...");
115         }
116
117         if (is_bin)
118         {
119                 int i = 0;
120 #ifdef _PSP_FW_VERSION
121                 int bufs = (read_len*2048) / (2048+304);
122                 pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
123                 for (i = 1; i < bufs; i++)
124                         // should really use memmove here, but my memcpy32 implementation is also suitable here
125                         memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
126 #endif
127                 for (; i < read_len - 1; i++)
128                 {
129                         pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
130                         // pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
131                 }
132                 // further data might be moved, do not overwrite
133                 pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
134                 pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
135         }
136         else
137         {
138                 pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
139         }
140         memcpy32(dest, (int *) cd_buffer, 2048/4);
141         prev_lba = lba;
142
143         if (moved)
144         {
145                 /* file pointer must point to the same data in file, as would-be data after our buffer */
146                 int where_seek;
147                 lba += PicoCDBuffers;
148                 where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
149                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
150         }
151 }
152