michaelh@juju.net.nz
$Id: sdcc.html,v 1.1.1.1 2005/03/15 06:05:14 michaelh Exp $
News | Snapshots | Last release | Bug tracking | Links
The idea is to re-target SDCC, a free GPL'ed retargettable C compiler designed for embedded systems to the Zilog Z80 and now the Nintendo Gameboy.
sdcc recently moved to sourceforge.net. The z80 port is now part of the standard code base, which is available via anonymous cvs from cvs.sdcc.sourceforge.net. Have a look at the Sourceforge documentation for more information. Weekly snapshots are available here. Note that they're untested and may not build. This is a very simple Java based Z80 emulator which I'm using to test the generated code.
20th Nov 99: It can currently compile:
#include "debug.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "fs_internal.h"
#include "fs.h"
#include "errorno.h"
static BYTE *_disk;
#define DEBUG_INODE_SEEK 0
#define MAX_MMAPED_SECTORS 3
/** Used to make the emulation more true to life */
static INT8 _sectors_mmaped;
static BOOLEAN _in_sector_allocate;
/** Map a whole sector into memory.
Note that there is a limit to how many sectors can be in memory at once.
@param sector Absolute sector to mmap.
@return Pointer to the start of the sector in memory.
*/
void *sector_mmap(SECTOR sector)
{
assert(sector<NUM_SECTORS);
assert(!((sector == 0) && (_in_sector_allocate == FALSE)));
if (_sectors_mmaped == MAX_MMAPED_SECTORS) {
assert(0);
return NULL;
}
_sectors_mmaped++;
return _disk + (sector*SECTOR_LENGTH);
}
/** Release a previosally mmap'd sector.
@param sector Pointer returned from sector_mmap()
@param fIsDirty TRUE if the sector was modified and should be commited.
@return ERR_OK on success
*/
ERROR sector_release(void *pSector, BOOLEAN fIsDirty)
{
_sectors_mmaped--;
assert(_sectors_mmaped>=0);
return ERR_OK;
}
/** Allocate a new sector from the free pool.
Allocates sequentially.
@return The sector number of the just allocated sector
or INVALID_SECTOR on disk full.
*/
SECTOR sector_allocate(void)
{
/* Search the sector allocation table, and return the first one free */
/* PENDING: just so happens that the SAT is one sector long. Extend */
BYTE *pSector, *pWalk;
BYTE bLeft = 0;
SECTOR sector = 0;
_in_sector_allocate = TRUE;
if ((pSector = sector_mmap(SAT_SECTOR))) {
pWalk = pSector;
/* Search */
do {
if (*pWalk != 0xFF) {
BYTE bBits = *pWalk;
/* Found a free sector - get it's bit */
while (bBits) {
sector++;
bBits>>=1;
}
/* Set the bit in the SAT */
*pWalk |= (1<<(sector&7));
sector_release(pSector, TRUE);
_in_sector_allocate = FALSE;
return sector;
}
sector+=8;
pWalk++;
} while (--bLeft);
/* No room */
_in_sector_allocate = FALSE;
sector_release(pSector, FALSE);
}
assert(0);
return INVALID_SECTOR;
}
/** Seek to an offset within a handle.
Modes:
FS_SEEK_SET - iOffset is absolute from the start of the file.
FS_SEEK_CUR - iOffset is relative to the current position.
FS_SEEK_END - iOffset is relative to the end of the file.
@param pHandle The handle to seek in.
@param iOffset The offset to use.
@param bMode The seek mode FS_SEEK_*
*/
ERROR inode_seek(INODE_HANDLE *pHandle, INT16 iOffset, BYTE bMode)
{
INODE_HEADER *pHeader;
FS_LENGTH absPos;
assert(pHandle);
switch (bMode) {
case FS_SEEK_SET:
absPos = iOffset;
break;
case FS_SEEK_CUR:
absPos = pHandle->abs_offset + iOffset;
break;
case FS_SEEK_END:
absPos = pHandle->length + iOffset;
break;
default:
assert(0);
}
pHandle->abs_offset = absPos;
#if DEBUG_INODE_SEEK
dprintf("inode_seek: seeking to %u on %u\n", absPos, pHandle->root_sector);
#endif
if ((pHeader = sector_mmap(pHandle->root_sector))) {
if (pHeader->length < absPos) {
sector_release(pHeader, FALSE);
return ERR_FILE;
}
absPos += sizeof(INODE_HEADER);
pHandle->sector_offset = absPos&(SECTOR_LENGTH-1);
/* Note that when absPos == file length, these calculations
are invalid. */
if (absPos < SECTOR_LENGTH) {
/* Inside the first sector */
pHandle->current_sector = pHandle->root_sector;
}
else if (absPos < SECTOR_LENGTH*NUM_SECTOR_ENTRIES) {
pHandle->current_sector = pHeader->sectors[(absPos/SECTOR_LENGTH)-1];
}
else {
SECTOR *pSectors;
SECTOR sector;
sector = pHeader->extended;
sector_release(pHeader, FALSE);
if ((pSectors = sector_mmap(sector))) {
pHandle->current_sector = pSectors[(absPos>>SECTOR_LENGTH_EXP)-NUM_SECTOR_ENTRIES];
sector_release(pSectors, FALSE);
return ERR_OK;
}
else {
assert(0);
return ERR_FILE;
}
}
sector_release(pHandle, FALSE);
return ERR_OK;
}
return ERR_FILE;
}