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