2009-11-21 01:45:08 +00:00
|
|
|
#include <cstring>
|
|
|
|
|
2010-06-26 03:39:14 +00:00
|
|
|
#include <ProDOS/Bitmap.h>
|
2011-03-13 16:02:30 +00:00
|
|
|
#include <Device/BlockDevice.h>
|
|
|
|
#include <Cache/BlockCache.h>
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2010-06-26 03:39:14 +00:00
|
|
|
using namespace ProDOS;
|
2009-11-24 04:57:41 +00:00
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
// returns # of 1-bits set (0-8)
|
|
|
|
inline static unsigned popCount(uint8_t x)
|
|
|
|
{
|
|
|
|
#ifdef __GNUC__
|
|
|
|
return __builtin_popcount(x);
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Brian Kernighan / Peter Wegner in CACM 3 (1960), 322.
|
|
|
|
|
|
|
|
unsigned count;
|
|
|
|
for (count = 0; x; ++count)
|
|
|
|
{
|
|
|
|
x &= x - 1;
|
|
|
|
}
|
|
|
|
return count;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Bitmap::Bitmap(unsigned blocks)
|
|
|
|
{
|
|
|
|
_blocks = _freeBlocks = blocks;
|
|
|
|
|
|
|
|
_bitmapBlocks = (blocks + 4095) / 4096;
|
|
|
|
_freeIndex = 0;
|
|
|
|
|
|
|
|
unsigned bitmapSize = _bitmapBlocks * 512;
|
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
_bitmap.reserve(bitmapSize);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
// mark blocks as free..
|
|
|
|
_bitmap.resize(blocks / 8, 0xff);
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
// edge case...
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
if (blocks & 0x0f)
|
|
|
|
{
|
|
|
|
_bitmap.push_back( ~(0xff >> (blocks & 0x0f)) );
|
|
|
|
}
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
// mark any trailing blocks as in use.
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
_bitmap.resize(bitmapSize, 0x00);
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
Bitmap::Bitmap(Device::BlockCache *cache, unsigned keyPointer, unsigned blocks)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
|
|
|
_blocks = blocks;
|
|
|
|
_freeBlocks = 0;
|
|
|
|
_freeIndex = 0;
|
|
|
|
|
|
|
|
_bitmapBlocks = (blocks + 4095) / 4096;
|
|
|
|
|
|
|
|
unsigned bitmapSize = _bitmapBlocks * 512;
|
|
|
|
unsigned blockSize = blocks / 8;
|
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
_bitmap.reserve(bitmapSize);
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
// load the full block(s).
|
2009-11-21 01:45:08 +00:00
|
|
|
for (unsigned i = 0; i < blockSize; ++i)
|
|
|
|
{
|
2011-03-13 16:02:30 +00:00
|
|
|
uint8_t *buffer = (uint8_t *)cache->acquire(keyPointer);
|
|
|
|
|
|
|
|
_bitmap.insert(_bitmap.end(), buffer, buffer + 512);
|
|
|
|
|
|
|
|
cache->release(keyPointer);
|
|
|
|
|
|
|
|
keyPointer++;
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
// and any remaining partial block.
|
2009-11-21 01:45:08 +00:00
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
if (blocks & 4095)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
2011-03-13 16:02:30 +00:00
|
|
|
|
|
|
|
uint8_t *buffer = (uint8_t *)cache->acquire(keyPointer);
|
|
|
|
|
|
|
|
unsigned bits = blocks & 4095;
|
|
|
|
unsigned bytes = bits / 8;
|
|
|
|
|
|
|
|
//for (unsigned i = 0; i < bits / 8; ++i) _bitmap.push_back(buffer[i]);
|
|
|
|
|
|
|
|
_bitmap.insert(_bitmap.end(), buffer, buffer + bytes);
|
|
|
|
// partial...
|
|
|
|
|
|
|
|
if (blocks & 0x0f)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
2011-03-13 16:02:30 +00:00
|
|
|
uint8_t tmp = buffer[bytes];
|
|
|
|
tmp &= ~(0xff >> (blocks & 0x0f));
|
|
|
|
|
|
|
|
_bitmap.push_back(tmp);
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
2011-03-13 16:02:30 +00:00
|
|
|
|
|
|
|
// remainder set to in use.
|
|
|
|
_bitmap.resize(bitmapSize, 0x00);
|
|
|
|
|
|
|
|
cache->release(keyPointer);
|
|
|
|
|
|
|
|
keyPointer++;
|
|
|
|
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
2011-03-13 16:02:30 +00:00
|
|
|
|
|
|
|
// now set _freeBlocks and _freeIndex;
|
|
|
|
std::vector<uint8_t>::iterator iter;
|
|
|
|
|
|
|
|
_freeIndex = -1;
|
|
|
|
for (iter = _bitmap.begin(); iter != _bitmap.end(); ++iter)
|
|
|
|
{
|
|
|
|
_freeBlocks += popCount(*iter);
|
|
|
|
if (_freeIndex == -1 && *iter)
|
|
|
|
_freeIndex = std::distance(_bitmap.begin(), iter);
|
|
|
|
}
|
2009-11-21 01:45:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Bitmap::~Bitmap()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void Bitmap::freeBlock(unsigned block)
|
|
|
|
{
|
|
|
|
if (block >= _blocks) return;
|
|
|
|
|
|
|
|
unsigned index = block / 8;
|
|
|
|
unsigned offset = block & 0x07;
|
|
|
|
unsigned mask = 0x80 >> offset;
|
|
|
|
|
|
|
|
uint8_t tmp = _bitmap[index];
|
|
|
|
|
|
|
|
if ((tmp & mask) == 0)
|
|
|
|
{
|
|
|
|
++_freeBlocks;
|
|
|
|
_bitmap[index] = tmp | mask;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Bitmap::allocBlock(unsigned block)
|
|
|
|
{
|
|
|
|
if (block >= _blocks) return -1;
|
|
|
|
|
|
|
|
|
|
|
|
unsigned index = block / 8;
|
|
|
|
unsigned offset = block & 0x07;
|
|
|
|
unsigned mask = 0x80 >> offset;
|
|
|
|
|
|
|
|
uint8_t tmp = _bitmap[index];
|
|
|
|
|
|
|
|
if ((tmp & mask))
|
|
|
|
{
|
|
|
|
--_freeBlocks;
|
|
|
|
_bitmap[index] = tmp & ~mask;
|
|
|
|
return block;
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int Bitmap::allocBlock()
|
|
|
|
{
|
|
|
|
if (!_freeBlocks) return -1;
|
|
|
|
|
2009-11-24 04:57:41 +00:00
|
|
|
unsigned freeIndex = _freeIndex;
|
2009-11-21 01:45:08 +00:00
|
|
|
unsigned maxIndex = (_blocks + 7) / 8;
|
|
|
|
|
|
|
|
|
2009-11-24 04:57:41 +00:00
|
|
|
for (unsigned index = _freeIndex; index < maxIndex; ++index)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
|
|
|
uint8_t tmp = _bitmap[index];
|
|
|
|
if (!tmp) continue;
|
|
|
|
|
|
|
|
unsigned mask = 0x80;
|
|
|
|
for (unsigned offset = 0; offset < 8; ++offset)
|
|
|
|
{
|
|
|
|
if (tmp & mask)
|
|
|
|
{
|
2009-11-24 04:57:41 +00:00
|
|
|
_freeIndex = index;
|
2009-11-21 01:45:08 +00:00
|
|
|
_bitmap[index] = tmp & ~mask;
|
|
|
|
--_freeBlocks;
|
|
|
|
return index * 8 + offset;
|
|
|
|
}
|
|
|
|
mask = mask >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-24 04:57:41 +00:00
|
|
|
for (unsigned index = 0; index < freeIndex; ++index)
|
2009-11-21 01:45:08 +00:00
|
|
|
{
|
|
|
|
uint8_t tmp = _bitmap[index];
|
|
|
|
if (!tmp) continue;
|
|
|
|
|
|
|
|
unsigned mask = 0x80;
|
|
|
|
for (unsigned offset = 0; offset < 8; ++offset)
|
|
|
|
{
|
|
|
|
if (tmp & mask)
|
|
|
|
{
|
2009-11-24 04:57:41 +00:00
|
|
|
_freeIndex = index;
|
2009-11-21 01:45:08 +00:00
|
|
|
_bitmap[index] = tmp & ~mask;
|
|
|
|
--_freeBlocks;
|
|
|
|
return index * 8 + offset;
|
|
|
|
}
|
|
|
|
mask = mask >> 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// should never happen...
|
|
|
|
return -1;
|
|
|
|
}
|