📄 buffer.c
字号:
//++
//buffer.c - Disk Buffer Management Functions
//
// Copyright (C) 2005 by Spare Time Gizmos. All rights reserved.
//
// This file is part of the Spare Time Gizmos' MP3 Player firmware.
//
// This firmware is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 59 Temple
// Place, Suite 330, Boston, MA 02111-1307 USA.
//
//DESCRIPTION:
// Rather than fixed, statically allocated buffers for reading FATs, direct-
// ory data, and MP3 file data from the CF card, this code uses a somewhat more
// elaborate scheme. A number (usually 4 or 8, depending on the MCU RAM size)
// of 512 byte buffers are allocated at system initialization time, and each one
// of these buffers has a buffer control block (aka BCB) associated with it.
// The BCBs themselves are stored in IDATA and each BCB keeps track of
//
// * the address (in XDATA) of the associated 512 byte buffer
// * a count of the bytes used in this buffer
// * and a link to another BCB, for chaining BCBs together
//
// All BCBs are initially put on a free list, and the code can pull buffers
// off of the free list as they are needed. When the code is done with a
// buffer, it simply returns it to the free list. Simple, no? For playing
// MP3 data, the MP3DRQ code actually keeps another queue of buffers which
// contain MP3 data; the background process reads data from the file and
// places filled buffers on this queue, and the MP3DRQ code removes filled
// buffers, sends them to the STA013, and then puts them back on the free
// list.
//
// Although it sounds complex, it's actually not that hard and this system
// does have a few advantages:
//
// * Since the actual buffers in XDATA are always aligned on 512 byte boundaries,
// the address arithmetic to calculate buffer indicies is greatly simplified.
//
// * Since the BCBs themselves are stored in IDATA, entire buffers can be moved
// from one list to another by manipulating single byte pointers.
//
// * There are no special case conditions in the playing code for wrap around as
// there would be with a circular buffer.
//
// * It's easy for functions that need a temporary disk buffer (e.g. the ID3 tag
// reader) to pull disk sector buffers "out of the rotation", use them for a
// few moments, and then return them to the free pool.
//
//REVISION HISTORY:
// dd-mmm-yy who description
// 28-May-05 RLA New file.
// 12-OCT-05 RLA Implement cbReserved parameter for InitializeBuffers().
// Create as many buffers as we can, starting from the top
// of external RAM and working downwards...
// 19-Oct-05 RLA Add STACKSLOCS hack to InitializeBuffers() for SDCC.
//--
// Include files...
#include <stdio.h> // needed so DBGOUT(()) can find printf!
#include "standard.h" // standard types - BYTE, WORD, BOOL, etc
#include "player.h" // project wide (hardware configuration) declarations
#include "post.h" // RAMSize(), et al...
#include "cfcard.h" // needed for IDE_SECTOR_SIZE
#include "buffer.h" // declarations for this module
// This is the free buffer queue...
PUBLIC PIBCB g_pFreeBufferList;
// And this allocates idata space for the actual buffer control blocks.
// Note that this doesn't need to be public - all the rest of the modules
// interact with the BCBs by means of pointers which they obtain (or _should_
// obtain!) from the free buffer pool.
PRIVATE BUFFER_CONTROL_BLOCK IDATA m_aBufferControlBlocks[MAX_NUMBER_OF_BUFFERS];
//++
// This routine will allocate XDATA RAM for the disk buffer pool. The exact
// number of buffers that can be created is limited both by the size of XRAM
// and the number of buffer control blocks. Although the buffers themselves
// are allocated in XDATA, the buffer control blocks (BCBs) themselves are stored
// in IDATA and there are a limited number of BCBs (currently 4) available. Thus
// on a P89C664 processor with 1792 bytes of XDATA RAM, we can allocate only three
// buffers maximum, 1536 bytes, and the remaining BCBs go unused. However, on the
// P89C668 MCU (7936 bytes of XDATA RAM) we can allocate only as many buffers as
// we have BCBs, and the remaining XRAM goes unused.
//
// [BTW, the Philips marketing literature says the '664 has 2K of RAM and that
// the P89C668 has 8K. Don't believe them - turns out they're counting the 256
// bytes of 8051 internal IDATA/DATA RAM in that total! The actual amount of real
// XDATA memory is only 1792 or 7936 bytes!]
//
// This routine uses the RAMSize() function to determine the amount of XDATA RAM
// and then allocates the buffers downward, starting from the highest RAM address,
// until we run out of RAM or BCBs, which ever comes first. The cbReserved
// parameter specifies the number of bytes of XDATA that are to be reserved for
// static XDATA variables. Remember that static variables are allocated by the
// linker from the bottom (lowest address) UP, which is why buffers are allocated
// top down. For example, on a P89C664 MCU, with RAMSize() == 1536, and cbReserved
// == 512, we can fit two disk buffers.
//
// Lastly, don't agonize too much over fine tuning the value of cbReserved. For
// example, in the previous case, unless you can reduce cbReserved below 256 bytes
// (pretty much not possible in the current code), nothing will change. Since disk
// buffers are always 512 bytes, whether cbReserved == 512, 600, 400 or even 300,
// there's still only room for two buffers.
//--
PUBLIC void InitializeBuffers (WORD cbReserved) STACKSLOCS
{
BYTE i; PXBYTE pbFree;
pbFree = (PXBYTE) RAMSize();
g_pFreeBufferList = NULL;
DBGOUT(("Buffers allocated at"));
for (i = 0; i < MAX_NUMBER_OF_BUFFERS; ++i) {
pbFree -= IDE_SECTOR_SIZE;
if ((WORD) pbFree < cbReserved) break;
m_aBufferControlBlocks[i].pNext = g_pFreeBufferList;
m_aBufferControlBlocks[i].pbBuffer = pbFree;
m_aBufferControlBlocks[i].cbBuffer = 0;
DBGOUT((" %04X", (WORD) pbFree));
//DBGOUT(("InitializeBuffers: Buffer# %bd, pNext=0x%02bX, pbBuffer=0x%04X\n",
// i, (BYTE) m_aBufferControlBlocks[i].pNext, (WORD) m_aBufferControlBlocks[i].pbBuffer));
g_pFreeBufferList = &(m_aBufferControlBlocks[i]);
}
DBGOUT((" (%bd buffers) ...\n", (BYTE) i));
//DBGOUT(("InitializeBuffers: m_pFreeBufferList=0x%02bX\n", (BYTE) m_pFreeBufferList));
}
//++
// This routine is used for debugging memory leak problems. It will show a
// list of the currently free buffers and, as a side effect, return a count
// of them...
//--
#ifdef DEBUG
PUBLIC BYTE ShowBufferPool (void)
{
PIBCB piBCB; BYTE bFree = 0;
//DBGOUT(("Free buffers: "));
for (piBCB = g_pFreeBufferList; piBCB != NULL; piBCB = piBCB->pNext) {
//DBGOUT((" %04X", (WORD) (piBCB->pbBuffer)));
++bFree;
}
//DBGOUT(("\n"));
return bFree;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -