826184b5284d46631621d55cb492b530410697de
[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 void PicoCDBufferFlush(void)
51 {
52         prev_lba = 0x80000000;
53 }
54
55
56 /* this is was a try to fight slow SD access of GP2X */
57 PICO_INTERNAL void PicoCDBufferRead(void *dest, int lba)
58 {
59         int is_bin, offs, read_len, moved = 0;
60         reads++;
61
62         is_bin = Pico_mcd->TOC.Tracks[0].ftype == TYPE_BIN;
63
64         if (PicoCDBuffers <= 0)
65         {
66                 /* no buffering */
67                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
68                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
69                 pm_read(dest, 2048, Pico_mcd->TOC.Tracks[0].F);
70                 return;
71         }
72
73         /* hit? */
74         offs = lba - prev_lba;
75         if (offs >= 0 && offs < PicoCDBuffers)
76         {
77                 hits++;
78                 if (offs == 0) dprintf("CD buffer seek to old %i -> %i\n", prev_lba, lba);
79                 memcpy32(dest, (int *)(cd_buffer + offs*2048), 2048/4);
80                 return;
81         }
82
83         if (prev_lba + PicoCDBuffers != lba)
84         {
85                 int where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
86                 dprintf("CD buffer seek %i -> %i\n", prev_lba, lba);
87                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
88         }
89
90         dprintf("CD buffer miss %i -> %i\n", prev_lba, lba);
91
92         if (lba < prev_lba && prev_lba - lba < PicoCDBuffers)
93         {
94                 read_len = prev_lba - lba;
95                 dprintf("CD buffer move=%i, read_len=%i", PicoCDBuffers - read_len, read_len);
96                 memmove(cd_buffer + read_len*2048, cd_buffer, (PicoCDBuffers - read_len)*2048);
97                 moved = 1;
98         }
99         else
100         {
101                 read_len = PicoCDBuffers;
102         }
103
104         if (PicoMessage != NULL && read_len >= 512)
105         {
106                 PicoMessage("Buffering data...");
107         }
108
109         if (is_bin)
110         {
111                 int i = 0;
112 #if REDUCE_IO_CALLS
113                 int bufs = (read_len*2048) / (2048+304);
114                 pm_read(cd_buffer, bufs*(2048+304), Pico_mcd->TOC.Tracks[0].F);
115                 for (i = 1; i < bufs; i++)
116                         // should really use memmove here, but my memcpy32 implementation is also suitable here
117                         memcpy32((int *)(cd_buffer + i*2048), (int *)(cd_buffer + i*(2048+304)), 2048/4);
118 #endif
119                 for (; i < read_len - 1; i++)
120                 {
121                         pm_read(cd_buffer + i*2048, 2048 + 304, Pico_mcd->TOC.Tracks[0].F);
122                         // pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR); // seeking is slower, in PSP case even more
123                 }
124                 // further data might be moved, do not overwrite
125                 pm_read(cd_buffer + i*2048, 2048, Pico_mcd->TOC.Tracks[0].F);
126                 pm_seek(Pico_mcd->TOC.Tracks[0].F, 304, SEEK_CUR);
127         }
128         else
129         {
130                 pm_read(cd_buffer, read_len*2048, Pico_mcd->TOC.Tracks[0].F);
131         }
132         memcpy32(dest, (int *) cd_buffer, 2048/4);
133         prev_lba = lba;
134
135         if (moved)
136         {
137                 /* file pointer must point to the same data in file, as would-be data after our buffer */
138                 int where_seek;
139                 lba += PicoCDBuffers;
140                 where_seek = is_bin ? (lba * 2352 + 16) : (lba << 11);
141                 pm_seek(Pico_mcd->TOC.Tracks[0].F, where_seek, SEEK_SET);
142         }
143 }
144