/* * * DISCLAIMER: * * This program is provided as a service to the programmer * community to demonstrate one or more features of the Amiga * personal computer. These code samples may be freely used * for commercial or noncommercial purposes. * * Commodore Electronics, Ltd ("Commodore") makes no * warranties, either expressed or implied, with respect * to the program described herein, its quality, performance, * merchantability, or fitness for any particular purpose. * This program is provided "as is" and the entire risk * as to its quality and performance is with the user. * Should the program prove defective following its * purchase, the user (and not the creator of the program, * Commodore, their distributors or their retailers) * assumes the entire cost of all necessary damages. In * no event will Commodore be liable for direct, indirect, * incidental or consequential damages resulting from any * defect in the program even if it has been advised of the * possibility of such damages. Some laws do not allow * the exclusion or limitation of implied warranties or * liabilities for incidental or consequential damages, * so the above limitation or exclusion may not apply. * */ /***************************************************************************** * * FreeMap program creates a visual diagram of free memory * * =Robert J. Mical= * 9 January 1986 * * Copyright (C) 1986, COMMODORE-AMIGA, INC. * All Rights Reserved * ****************************************************************************/ #include "freemap.h" #define SCREENWIDTH 320 #define SCREENHEIGHT 36 #define STARTLINE 6 #define STARTCOLUMN (2 + 4) #define LEFTOFFSET 6 #define MENU_INFO 2 #define MENU_REDISPLAY 1 #define MENU_QUIT 0 #define SCREENBYTEWIDTH 40 #define MAPBYTEWIDTH 32 /* must be a power of two */ #define MAX_BLOCK_COUNT ((512 * 1024) >> 6) struct IntuitionBase *IntuitionBase; struct GfxBase *GfxBase; extern struct ExecBase *SysBase; struct TextAttr SafeFont = { "topaz.font", 8, 0, 0, }; struct IntuiText PleaseText = { 0, 1, JAM2, 1, 1, NULL, "Please", NULL, }; struct MenuItem PleaseItem = { NULL, 0, 0, 88, 9, ITEMTEXT | ITEMENABLED | HIGHCOMP, 0, (APTR)&PleaseText, NULL, 0, NULL, NULL, }; struct Menu MapMenus[] = { { NULL, 10, 0, 48, 0, MENUENABLED, "Info", &PleaseItem, }, { &MapMenus[0], 58, 0, 88, 0, MENUENABLED, "Redisplay", &PleaseItem, }, { &MapMenus[1], 146, 0, 48, 0, MENUENABLED, "Quit", &PleaseItem, }, }; struct NewScreen MapScreen = { 0, 200 - SCREENHEIGHT, SCREENWIDTH, SCREENHEIGHT, 1, 0, 1, NULL, CUSTOMSCREEN, &SafeFont, NULL, NULL, NULL, }; struct NewWindow MapWindow = { LEFTOFFSET, 0, (MAPBYTEWIDTH << 3) + 4, SCREENHEIGHT, -1, -1, MENUPICK | MENUVERIFY, SMART_REFRESH | BACKDROP | BORDERLESS | NOCAREREFRESH, NULL, NULL, NULL, NULL, NULL, 0, 0, 0, 0, CUSTOMSCREEN, }; struct Screen *MyScreen; struct Window *MyWindow; SHORT BitsAvailable; SHORT BlockCount; BYTE BitsValue; SHORT WidthIndex; UBYTE *MemBlock; UBYTE *MapPointer; ShiftMask[8] = { 0xFF, 0X01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, }; RestartWindow() /* This routine clears the window and then draws the border */ { SetRast(MyWindow->RPort, 0); Move(MyWindow->RPort, 0, 0); Draw(MyWindow->RPort, 0, SCREENHEIGHT - 1); Draw(MyWindow->RPort, (MAPBYTEWIDTH << 3)+4-1, SCREENHEIGHT - 1); Draw(MyWindow->RPort, (MAPBYTEWIDTH << 3) + 4 - 1, 0); Draw(MyWindow->RPort, 0, 0); } BumpMapPointer() /* This routine bumps the MapPointer variable, which variable contains the * pointer to the byte in the Screen's BitMap which is to receive the * next FreeMap bits. */ { WidthIndex++; if (WidthIndex == MAPBYTEWIDTH) { /* We're at the right edge of the map window, so skip ahead * to the left edge of the next line */ WidthIndex = 0; MapPointer += (SCREENBYTEWIDTH - MAPBYTEWIDTH + 1); } else MapPointer++; } ShiftInBits(bitcount) SHORT bitcount; /* This routine "shifts" the next set of bits into the memory map */ { SHORT shift, bytecount; if (BitsAvailable & 0x7) { /* There's less than a whole byte available, so we must start * by shifting. Get the shift amount, which will be either all * of the bits that are available, or the block count if it's less * than the count of the available bits */ if (bitcount > BitsAvailable) shift = BitsAvailable; else shift = bitcount; /* Shift the current contents of this byte of the map * out of the way of our new bits. */ *MapPointer <<= shift; /* The above shift shifts zero bits in from the right. * If the current BitsValue is clear, leave them zero, else set our * new bits. */ if (BitsValue) *MapPointer |= ShiftMask[shift]; /* Reduce the block count by the number of bits we just arranged */ bitcount -= shift; /* if we've used up this memory map byte, advance to the next one */ if ((BitsAvailable -= shift) == 0) { BitsAvailable = 8; BumpMapPointer(); } } /* Now that we've taken care of any partially completed Map bytes, * let's check for any whole bytes that we can set (speed!) */ bytecount = bitcount >> 3; while (bytecount) { *MapPointer = BitsValue; BumpMapPointer(); bytecount--; } /* Finally, do any remaining bitcount bits to be set */ if (bitcount &= 0x7) { *MapPointer = BitsValue; /* Cheating, in a sense, but FAST! */ BitsAvailable = 8 - bitcount; } } SHORT FindFreeBlock() /* This routine feels through the memory-free list, looking for a block * of free memory that is big enough to qualify as being a block. * A block starts on 64-byte boundaries and is 64-bytes wide. For a * block to be considered "free" all of the 64 bytes must be free */ { SHORT firstwholeblock, nextrealblock; FOREVER { if (MemBlock == 0) return(0); firstwholeblock = (LONG)(MemBlock + 63) >> 6; nextrealblock = (LONG)( MemBlock + ((struct MemChunk *)MemBlock)->mc_Bytes ) >> 6; MemBlock = (UBYTE *)((struct MemChunk *)MemBlock)->mc_Next; if (firstwholeblock < nextrealblock) { BlockCount = nextrealblock - firstwholeblock; return(firstwholeblock); } } } SetTimer(sec, micro, timermsg) ULONG sec, micro; struct IOStdReq *timermsg; /* This routine simply sets the timer to interrupt us after secs.micros */ { timermsg->io_Command = TR_ADDREQUEST; /* add a new timer request */ timermsg->io_Actual = sec; /* seconds */ timermsg->io_Length = micro; /* microseconds */ SendIO(timermsg); /* post a request to the timer */ } main() { struct MsgPort *timerport; struct IOStdReq *timermsg; struct MemHeader *MemHeader; SHORT NextFreeBlock, NextTakenBlock; ULONG wakeupbits, timerbit, windowbit; struct IntuiMessage *message; ULONG class; USHORT code; BOOL Redisplay; if ((IntuitionBase = (struct IntuitionBase *)OpenLibrary( "intuition.library", 0)) == 0) { printf("NO LIBRARY"); goto EXITING; } if ((GfxBase = (struct GfxBase *)OpenLibrary("graphics.library", 0)) == 0) { printf("NO LIBRARY"); goto EXITING; } if ((MyScreen = (struct Screen *)OpenScreen(&MapScreen)) == NULL) { printf("NO SCREEN"); goto EXITING; } ShowTitle(MyScreen, FALSE); SetRGB4(&MyScreen->ViewPort, 0, 15, 12, 8); SetRGB4(&MyScreen->ViewPort, 1, 8, 0, 0); MapWindow.Screen = MyScreen; if ((MyWindow = (struct Window *)OpenWindow(&MapWindow)) == NULL) { printf("NO WINDOW"); goto EXITING; } SetMenuStrip(MyWindow, &MapMenus[2]); SetFont(MyWindow->RPort, OpenFont(&SafeFont)); Move(&MyScreen->RastPort, (MAPBYTEWIDTH << 3) + 8 + 4, 18); Text(&MyScreen->RastPort, "512K", 4); Move(&MyScreen->RastPort, (MAPBYTEWIDTH << 3) + 8 + 4, 26); Text(&MyScreen->RastPort, "MEMORY", 6); Move(&MyScreen->RastPort, (MAPBYTEWIDTH << 3) + 8 + 4, 34); Text(&MyScreen->RastPort, "MAP", 3); RestartWindow(); timerport = (struct MsgPort *)CreatePort(0, 0); if (timerport == 0) goto EXITING; timermsg = (struct IOStdReq *)CreateStdIO(timerport); if (timermsg == 0) goto EXITING; if (OpenDevice(TIMERNAME, UNIT_VBLANK, timermsg, 0) != 0) goto EXITING; timerbit = 1 << timerport->mp_SigBit; windowbit = 1 << MyWindow->UserPort->mp_SigBit; SetTimer(2, 0, timermsg); Redisplay = TRUE; FOREVER { if (Redisplay) { /* This program draws the memory map information right into * the BitMap of the Screen, rather than using the graphics * support library routines to draw into the Window. * There is nothing illegal or immoral about doing this, but * is does require a thorough knowledge of how Intuition and * the graphics library create and manipulate the display. * In other words, this is *not* something that the novice * will want to do lightly, but the soon-to-be-expert may * want to examine as an example of how to do meta-graphics * in the Amiga window environment. */ MapPointer = MyScreen->RastPort.BitMap->Planes[0]; MapPointer += (SCREENBYTEWIDTH * 2 + 1); Forbid(); do MemHeader = (struct MemHeader *)SysBase->MemList.lh_Head; while ((MemHeader->mh_Attributes & MEMF_CHIP) == 0); MemBlock = (UBYTE *)MemHeader->mh_First; BitsAvailable = 8; WidthIndex = 0; NextTakenBlock = 0; do { if (NextFreeBlock = FindFreeBlock()) { BitsValue = 0; ShiftInBits(NextFreeBlock - NextTakenBlock); BitsValue = -1; ShiftInBits(BlockCount); NextTakenBlock = NextFreeBlock + BlockCount; } else ShiftInBits(MAX_BLOCK_COUNT - NextTakenBlock); } while (MemBlock); if (NextTakenBlock < MAX_BLOCK_COUNT) { BitsValue = 0; ShiftInBits(MAX_BLOCK_COUNT - NextTakenBlock); } Permit(); } wakeupbits = Wait(timerbit | windowbit); if (wakeupbits & timerbit) { GetMsg(timerport); /* this does nothing more than "clear" */ SetTimer(2, 0, timermsg); } if (wakeupbits & windowbit) { message = (struct IntuiMessage *)GetMsg(MyWindow->UserPort); class = message->Class; code = message->Code; ReplyMsg(message); switch (class) { case MENUVERIFY: Redisplay = FALSE; break; case MENUPICK: switch (MENUNUM(code)) { case MENU_INFO: RestartWindow(); Move(MyWindow->RPort, STARTCOLUMN, STARTLINE); Text(MyWindow->RPort, "Each pixel represents 64 bytes.", 31); Move(MyWindow->RPort, STARTCOLUMN + 20, STARTLINE + 9); Text(MyWindow->RPort, "If all bytes are free, the", 26); Move(MyWindow->RPort, STARTCOLUMN, STARTLINE + 18); Text(MyWindow->RPort, "pixel is dark, else it's light.", 31); Move(MyWindow->RPort, STARTCOLUMN + 20, STARTLINE + 28); Text(MyWindow->RPort, "This trinket by =RJMical=", 26); break; case MENU_REDISPLAY: RestartWindow(); case NOMENU: Redisplay = TRUE; break; case MENU_QUIT: goto EXITING; } } } } EXITING: if (MyWindow) CloseWindow(MyWindow); if (MyScreen) CloseScreen(MyScreen); if (timerport) { Wait(timerbit); GetMsg(timerport); CloseDevice(timermsg); DeleteStdIO(timermsg); DeletePort(timerport); } }