…is always light

Tag Archives: Nostalgia

Quest of Love is an Amiga project that I never finished, but always wanted to create…

The project started as an assembly language project, but it was too much work, so I switched to C language. The video below shows, what I managed to do:

For curiosity and historical — on the other hand educational — reasons, I’ve decided to publish the C language source I have for this project. The assembly version is published in this old blog post..

The comments and names of some variables are in Finnish..

#include <math.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <graphics/gfx.h>
#include <graphics/displayinfo.h>
#include <graphics/modeid.h>
#include <intuition/intuition.h>
#include <dos/stdio.h>
#include <dos/dos.h>
#include <proto/exec.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>
#include <libraries/iff.h>

#define INTUI_V38_NAMES_ONLY

#define LIBVER 39

#define TURN 83

struct IntuitionBase *IntuitionBase=NULL;
struct GfxBase *GfxBase=NULL;
struct Library *IFFBase=NULL;

struct Screen *screen=NULL;
struct Window *window=NULL;

struct ViewPort *viewport;
struct RastPort *rastport;

ULONG   errorcode;

unsigned char *BM_block=NULL, *BM0, *BM1;
unsigned char *source0, *source1, *source2, *source3, *source4;
unsigned char *dest0, *dest1, *dest2, *dest3, *dest4;

struct BitMap blockbitmap = {2, 1088, 0, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
struct BitMap myBitMap0 = {40, 256, 0, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
struct BitMap myBitMap1 = {40, 256, 0, 5, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL};
struct BitMap *DrawBitMap=NULL,*ShowBitMap=NULL;

struct Monster {
    int x,y;
    WORD block;
    WORD vital;
    WORD exp;
    char frame;
    char delay;
    char elossa;
};

struct Monster Monsters[21];
struct Monster MonType[1];

int Blocked(int x, int y, short suunta);
void    DoubleBuffering(short *);
void    DrawMap(UWORD *Map);
void    DrawBlock(int,int,int);
void    Cycle(void);
void  HandleMonsters(void);
void  InitMonsters(void);
void    SetDelay(WORD,WORD);
void  DeAllocateResources();
char  ReadMapFile(char [], UWORD *buffer, int lkm);

int cind, block, k, j;
UWORD colortable[32];
UWORD copytable[4];
UWORD *buffer=NULL;
LONG  count;

UWORD *Map = NULL;
UWORD *WorldMap = NULL;
int   map_width, map_heigth;

WORD MapX=0, MapY=0,isoX=0,isoY=0;
char delay=-1;
char turn=TURN;



int main(void) {

    short   keepgoing=TRUE;
    struct  IntuiMessage *msg;
    ULONG       class;
    UWORD       code,qualifier;
    IFFL_HANDLE iff=NULL;
    short       *Which;

    if((GfxBase=(struct GfxBase *)
    OpenLibrary("graphics.library",LIBVER))==NULL)
    {
      printf("graphics open failed (V39 kickstart required)\n");
      DeAllocateResources();
      exit(1);
    }

    if((IntuitionBase=(struct IntuitionBase *)
    OpenLibrary("intuition.library",LIBVER))==NULL)
    {
      printf("intuition open failed (V39 mkickstart required)\n");
      DeAllocateResources();
      exit(1);
    }

    IFFBase=(struct Library*)OpenLibrary(IFFNAME, IFFVERSION);
    if (IFFBase == NULL) {
      printf("Can not open iff.library\n");
      DeAllocateResources();
      exit(1);
    }
    
    BM_block = (unsigned char *)AllocMem(11520, MEMF_CHIP);
    if (!BM_block) {
      printf("Memory allocation failed\n");
      DeAllocateResources();
      exit(1);
    }
    
    BM0 = (unsigned char *)AllocMem(51200,MEMF_CHIP|MEMF_CLEAR);
    if (!BM0) {
      printf("Memory allocation failed\n");
      DeAllocateResources();
      exit(1);
    }
     
    BM1 = (unsigned char *)AllocMem(51200,MEMF_CHIP|MEMF_CLEAR);
    if (!BM1) {
      printf("Memory allocation failed\n");
      DeAllocateResources();
      exit(1);
     }

    buffer=(UWORD *)AllocMem(40, MEMF_CHIP);
    if (!buffer) {
      printf("Memory allocation failed\n");
      DeAllocateResources();
      exit(1);
    }
       
    InitMonsters();

    blockbitmap.Planes[0]=&BM_block[0];
    blockbitmap.Planes[1]=&BM_block[2176];
    blockbitmap.Planes[2]=&BM_block[4352];
    blockbitmap.Planes[3]=&BM_block[6528];
    blockbitmap.Planes[4]=&BM_block[8704];

    myBitMap0.Planes[0]=&BM0[0];
    myBitMap0.Planes[1]=&BM0[10240];
    myBitMap0.Planes[2]=&BM0[20480];
    myBitMap0.Planes[3]=&BM0[30720];
    myBitMap0.Planes[4]=&BM0[40960];

    myBitMap1.Planes[0]=&BM1[0];
    myBitMap1.Planes[1]=&BM1[10240];
    myBitMap1.Planes[2]=&BM1[20480];
    myBitMap1.Planes[3]=&BM1[30720];
    myBitMap1.Planes[4]=&BM1[40960];

    *Which=1;

    if((screen=OpenScreenTags(NULL,
        SA_Width, 320,
        SA_Height, 256,
        SA_Depth, 5,
        SA_Overscan, FALSE,
        SA_AutoScroll, TRUE,
        SA_Type, CUSTOMSCREEN|CUSTOMBITMAP,
        SA_DisplayID,PAL_MONITOR_ID,
        SA_PubName, "My Screen",
        SA_BitMap, &myBitMap0,
        TAG_END, NULL)
    )==NULL)
    {
        printf("Screen open failed\n");
      DeAllocateResources();
      exit(1);
    }

    if((window=OpenWindowTags(NULL,
        WA_Left, 0,
        WA_Top, 0,
        WA_Width, screen->Width,
        WA_Height, screen->Height,
        WA_IDCMP,IDCMP_VANILLAKEY,
        WA_Flags,WFLG_ACTIVATE|WFLG_RMBTRAP|WFLG_BORDERLESS,
        WA_ReportMouse, TRUE,
        WA_MinWidth,    50,
        WA_MinHeight,   20,
        WA_MaxWidth,    ~0,
        WA_MaxHeight,   ~0,
        WA_PubScreen,   screen,
        TAG_END, NULL)
    )==NULL)
    {
        printf("Window open failed\n");
        DeAllocateResources();
        exit(1);
    }

    viewport=&screen->ViewPort;
    rastport=window->RPort;

/* Bittikartoille on aiemmin varattu tila, mikä pitää laskea uudestaan, jos koko muuttuu */

    iff = IFFL_OpenIFF("Work:MyProjects/QoL/New/gfx/blocks16x1152.iff",IFFL_MODE_READ);
    if (!iff) {
      printf("IFF file open failed\n");
      DeAllocateResources();
      exit(1);
    }
  
    if (!(IFFL_DecodePic(iff, &blockbitmap))) {
      printf("IFF file decoding failed\n");
      DeAllocateResources();
      exit(1);
    }
 
    count = IFFL_GetColorTab(iff, colortable);
    LoadRGB4(&(screen->ViewPort), colortable, count);
    IFFL_CloseIFF(iff);

    iff = IFFL_OpenIFF("Work:MyProjects/QoL/IFFs/NewFrame.iff",IFFL_MODE_READ);
    if (!iff) {
      printf("IFF file open failed\n");
      DeAllocateResources();
      exit(1);
    }
    
    if (!(IFFL_DecodePic(iff,&myBitMap0))) {
      printf("IFF file decoding failed\n");
      DeAllocateResources();
      exit(1);
    }
       
    IFFL_CloseIFF(iff);

    for (int i=0; i<4; i++) copytable[i]=colortable[16+i];     BltBitMap(&myBitMap0,0,0,&myBitMap1,0,0,320,256,0xc0,0x1f,&buffer);     source0 = blockbitmap.Planes[0];     source1 = blockbitmap.Planes[1];     source2 = blockbitmap.Planes[2];     source3 = blockbitmap.Planes[3];     source4 = blockbitmap.Planes[4];     dest0 = screen->BitMap.Planes[0]+1001;
    dest1 = screen->BitMap.Planes[1]+1001;
    dest2 = screen->BitMap.Planes[2]+1001;
    dest3 = screen->BitMap.Planes[3]+1001;
    dest4 = screen->BitMap.Planes[4]+1001;

   WorldMap=(UWORD *)AllocMem(9920,MEMF_PUBLIC);
   if (WorldMap == NULL) {
      printf("Could not allocate memory for WorldMap\n");
      DeAllocateResources();
      exit(1);
   }
   
   if ((ReadMapFile("Work:Myprojects/QoL/Gamefield/Map11.gamefield",WorldMap,9920)) == 1) {
      DeAllocateResources();
      exit(1);
   }
    
   Map = WorldMap;
   map_width = 80;
   map_heigth = 62;

/* -------------------------------------------------------------------------- */
                                      
    while(keepgoing)
    {
        WaitTOF();
        DoubleBuffering(&Which);
        DrawMap(Map);
        HandlePlayer();
        HandleMonsters();
        GeneralRoutines();
        Cycle();
/*      printf("Delay %d ; Turn %d\n",delay,turn); */

/*      printf("Blocked %d\n",Blocked(MapX, MapY, 8)); */

        while(msg=(struct IntuiMessage *)GetMsg(window->UserPort))
       {
        class=msg->Class;
            code=msg->Code;
            qualifier=msg->Qualifier;
            ReplyMsg((struct Message *)msg);
/*          printf("%d\n",code); */

            switch(class) {
                case IDCMP_VANILLAKEY :
                     switch (code) {
                        case 27 : /* ESC */
                                    keepgoing=FALSE;
                                    DeAllocateResources();
                                    break;

/***
* Pelaajan ohjaus pääkartalla. Aluksi katsotaan, onko kulkusuunta blokattu;
* jos ei ole ja delay == -1 (eli maastotyypin viive on suoritettu), niin
* liikutaan
* painettuun kulkusuuntaan ja asetetaan uusi delay. Lisäksi tulostetaan
* joko kulkusuunta tai "Slow progress", jos viiveen takia kulkusuuntaan
* ei voinut mennä. Jos tulostettiin "Slow progress", niin delay-arvoa
* vähennetään yhdellä.

***/
                        case '2' : if (!Blocked(MapX, MapY, 2) && delay<0) {                                             MapY++;                                             isoY++;                                             if (MapY> map_heigth - 1) MapY=0;
                                            SetDelay(MapX,MapY);
                                            Print("South.",6);
                                     } else if (delay>-1) {
                                          Print("Slow progress.",14);
                                          delay--;
                                       }
                                    turn=TURN;
                                    break;

                        case '8' : if (!Blocked(MapX, MapY, 8) && delay<0) {
                                            MapY--;
                                            isoY--;
                                            if (MapY<0) MapY= map_heigth - 1;                                             SetDelay(MapX,MapY);                                             Print("North.",6);                                      } else if (delay>-1) {
                                          Print("Slow progress.",14);
                                          delay--;
                                       }
                                    turn=TURN;
                                    break;

                        case '6' : if (!Blocked(MapX, MapY, 6) && delay<0) {                                             MapX++;                                             isoX++;                                             if (MapX> map_width - 1) MapX=0;
                                            SetDelay(MapX,MapY);
                                            Print("East.",5);
                                        } else if (delay>-1) {
                                             Print("Slow progress.",14);
                                             delay--;
                                          }
                                    turn=TURN;
                                    break;

                        case '4' : if (!Blocked(MapX, MapY, 4) && delay<0) {
                                            MapX--;
                                            isoX--;
                                            if (MapX<0) MapX= map_width - 1;                                             SetDelay(MapX,MapY);                                             Print("West.",5);                                         } else if (delay>-1) {
                                             Print("Slow progress.",14);
                                             delay--;
                                    }
                                    turn=TURN;
                                    break;

                        case ' ' :  turn=TURN;
                                    Print("Pass.",5);
                                    break;
                }
          }

       }
    }
} /* END main */
 
void DeAllocateResources() {
    if (buffer) FreeMem(buffer,40);
/*  if (iff) IFFL_CloseIFF(iff); */
/*  if (BM0) FreeMem(BM0,51200);
    if (BM1) FreeMem(BM1,51200); */
    if (BM_block) FreeMem(BM_block,11520);
    if (window) CloseWindow(window);
    if (screen) CloseScreen(screen);
    if (BM0) FreeMem(BM0,51200);
    if (BM1) FreeMem(BM1,51200);
    if (GfxBase) CloseLibrary((struct Library *)GfxBase);
    if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
    if (IFFBase) CloseLibrary(IFFBase);
   if (WorldMap) FreeMem(WorldMap,9920);
}

void HandlePlayer(void) {
    DrawBlock(5,6,10);
}


void SetDelay(WORD x,WORD y) {
    x+=5; y+=6;
    if (x > map_width - 1) x=x - map_width;
    if (y > map_heigth - 1) y=y - map_heigth;
/*  printf("%d;%d; %d\n",x,y,Map[x+y*80]); */

    switch(Map[x+y*map_width]) {
      case 5 : delay=(char)Random(0,4); break;
      case 16: delay=(char)Random(0,2); break;
      default: delay=-1;
    }
/*  printf("%d\n",delay); */
}

void DoubleBuffering(short *Which) {
    switch(*Which) {
        case 0 : viewport->RasInfo->BitMap=&myBitMap0; *Which=1;
                    rastport->BitMap=&myBitMap1;
                    dest0 = myBitMap1.Planes[0]+1001;
                    dest1 = myBitMap1.Planes[1]+1001;
                    dest2 = myBitMap1.Planes[2]+1001;
                    dest3 = myBitMap1.Planes[3]+1001;
                    dest4 = myBitMap1.Planes[4]+1001;
                    DrawBitMap=&myBitMap1;
                    ShowBitMap=&myBitMap0;
                    break;
        case 1 : viewport->RasInfo->BitMap=&myBitMap1; *Which=0;
                    rastport->BitMap=&myBitMap0;
                    dest0 = myBitMap0.Planes[0]+1001;
                    dest1 = myBitMap0.Planes[1]+1001;
                    dest2 = myBitMap0.Planes[2]+1001;
                    dest3 = myBitMap0.Planes[3]+1001;
                    dest4 = myBitMap0.Planes[4]+1001;
                    DrawBitMap=&myBitMap0;
                    ShowBitMap=&myBitMap1;
                    break;
    }
    ScrollVPort(viewport);
}


/***
* Blocked-rutiini: Parametreina saadaan näkymän vasen yläkulma, mihin lisätään
* arvot, joilla saadan pelaajan sijainti eli näkymän keskikohta. Jos suunnassa,
* johon ollaan menossa on blocki, jonka päälle ei voi mennä palautetaan 1,
* mikä on merkkinä siitä, että hahmoa ei liikuteta, muutoin 0.
***/
int Blocked (int x, int y, short suunta) {
    int arvo;

    x+=5; y+=6;

    if (x > map_width - 1) x=x-map_width;
    if (y> map_heigth - 1) y=y- map_heigth;

/*  printf("Block: %d\n", Map[x+y*map_width]); */

    switch (suunta) {
        case 2 : y+=1; break;
        case 8 : y-=1; break;
        case 6 : x+=1; break;
        case 4 : x-=1; break;
    }

/*  printf("Block: %d\n", Map[x+y*map_width]); */

    switch (Map[x+y*map_width]) {
        case 3 :        arvo = 1; break;
        case 8 :        arvo = 1; break;
        case 12 :   arvo = 1; break;
        case 14 :   arvo = 1; break;
        default :   arvo = 0;
    }
    return arvo;
}


void DrawMap (UWORD *Map) {

/*  printf("DrawMap"); */

    int x,y,xg=0,yg=0,xx,yy;

    for (y=MapY,yg=0;y<MapY+14;y++,yg++) {
        for (x=MapX,xg=0;x<MapX+11;x++,xg++) { /*          printf("xx: %d", xx); */             if (x > map_width - 1) xx=x-map_width; else xx=x;
            if (y> map_heigth - 1) yy=y-map_heigth; else yy=y;

            if (x > map_width - 1 || y>map_heigth - 1) block = Map[xx+yy*map_width];
            else block = Map[x+y*map_width];

            block = block << 5;

            j=yg*640;
            for (int i=block; i<32+block; i++) {
                k=xg*2;
                dest0[k+j]=source0[i];
                i++; k++;
                dest0[k+j]=source0[i];
                j+=40;
            }

            j=yg*640;
            for (int i=block; i<32+block; i++) {
                k=xg*2;
                dest1[k+j]=source1[i];
                i++; k++;
                dest1[k+j]=source1[i];
                j+=40;
            }
    
            j=yg*640;
            for (int i=block; i<32+block; i++) {
                k=xg*2;
                dest2[k+j]=source2[i];
                i++; k++;
                dest2[k+j]=source2[i];
                j+=40;
            }

            j=yg*640;
            for (int i=block; i<32+block; i++) {
                k=xg*2;
                dest3[k+j]=source3[i];
                i++; k++;
                dest3[k+j]=source3[i];
                j+=40;
            }

            j=yg*640;
            for (int i=block; i<32+block; i++) {
                k=xg*2;
                dest4[k+j]=source4[i];
                i++; k++;
                dest4[k+j]=source4[i];
                j+=40;

            }

        }
    }
}


/* Koordinaatit blockeina */

void DrawBlock (int x, int y, int block) {

    block = block << 5;             /* kerrotaan 32:lla */

    j=y*640;                                /* kerrottaan 40 x 16:a */
    for (int i=block; i<32+block; i++) {
        k=x*2;
        dest0[k+j]=source0[i];
        i++; k++;
        dest0[k+j]=source0[i];
        j+=40;
    }

    j=y*640;
    for (int i=block; i<32+block; i++) {
        k=x*2;
        dest1[k+j]=source1[i];
        i++; k++;
        dest1[k+j]=source1[i];
        j+=40;
    }
    
    j=y*640;
    for (int i=block; i<32+block; i++) {
        k=x*2;
        dest2[k+j]=source2[i];
        i++; k++;
        dest2[k+j]=source2[i];
        j+=40;
    }

    j=y*640;
    for (int i=block; i<32+block; i++) {
        k=x*2;
        dest3[k+j]=source3[i];
        i++; k++;
        dest3[k+j]=source3[i];
        j+=40;
    }

    j=y*640;
    for (int i=block; i<32+block; i++) {
        k=x*2;
        dest4[k+j]=source4[i];
        i++; k++;
        dest4[k+j]=source4[i];
        j+=40;
    }

}

void Cycle (void) {
    int Rs = cind;

    for (int i=0; i<4; i++, Rs++) {         if (Rs > 3) Rs=0;
        colortable[i+16]=copytable[Rs];
    }
    cind++;
    if (cind > 3) cind = 0;

    LoadRGB4(&(screen->ViewPort), colortable, count);
}

void Print(char teksti[], int pituus) {
    ScrollRaster(rastport,0,8,195,119,300,245);
    Move(rastport,195,243);
    Text(rastport,teksti,pituus);
    BltBitMap(DrawBitMap,195,119,ShowBitMap,195,119,105,127,0xc0,0x1f,NULL);
}

char BlockedMonster(WORD x, WORD y, WORD count) {
    char i;

    for (i=0; i<21; i++) {
        if (Monsters[i].x==x && count!=i && Monsters[i].elossa==1)
            if (Monsters[i].y==y) return 1;
    }

    switch (Map[x+y*map_width]) {
        case 3 : return 1;
        case 8 : return 1;
        case 12 : return 1;
        case 14 : return 1;
        default : return 0;
    }

}

void HandleMonsters(void) {
    int i,apuX,apuY,RS;

    if (turn==TURN) {
        for(i=0; i<21; i++) {             if (Monsters[i].elossa) { /* 75% TN:llä lähdetään liikkeelle */                 RS=Random(0,4);                 if (RS>=1) {
                    apuX=Monsters[i].x;
                    apuY=Monsters[i].y;
                    RS=Random(0,2);
                    if (RS==0) {
                        if (isoX+5>apuX) apuX++; 
                        else apuX--; 
                        if (!BlockedMonster(apuX, apuY, i)) Monsters[i].x=apuX;
                    } else if (isoY+6>apuY) apuY++;
                         else apuY--; 
                    if (!BlockedMonster(apuX,apuY, i)) Monsters[i].y=apuY;
                }

            }
        }
    }

/* Laskeskellaan, piirretäänkö monsteria näkyviin */

    for(i=0; i<21; i++) {
        apuX=Monsters[i].x-isoX;
        apuY=Monsters[i].y-isoY;
        Monsters[i].frame=Monsters[i].block+Random(0,4);
        if (apuX<=10 && apuX>=0)
            if (apuY<=13 && apuY>=0) {
/*              printf("%d;%d\n",apuX,apuY); */
                DrawBlock(apuX,apuY,Monsters[i].frame);
            }
    }
}

void InitMonsters (void) {
    short type;

    MonType[0].block=64;
    MonType[0].vital=10;
    MonType[0].exp=10;
    MonType[0].delay=0;
    MonType[0].frame=64;

    for (int i=0; i<21; i++) {
        Monsters[i].x=Random(0,map_width);
        Monsters[i].y=Random(0,map_heigth);
        switch (Map[Monsters[i].x+Monsters[i].y*map_width]) {
            case 3,8,12,14 : Monsters[i].elossa=0; break;
            default : Monsters[i].elossa=1;
        }
            
        Monsters[i].block=64;
        type=Monsters[i].block;
        Monsters[i].vital=MonType[type-64].vital;
        Monsters[i].exp=MonType[type-64].exp;
        Monsters[i].delay=0;
        Monsters[i].frame=0;
    }

}


void GeneralRoutines() {
    turn--;
    if (turn<=0) { 
        delay--;
/*        printf("%d\n",delay); */
        if (delay<-1) delay=-1;
        turn=TURN;
        Print("Pass.",5);
    }

}

char ReadMapFile(char nimi[], UWORD *buffer, int koko) {
   BPTR file;
   LONG length;

/*   printf("%s\n",nimi); */

   file=Open(nimi,MODE_OLDFILE);
   length=Read(file,buffer,koko);

   if (length != koko) {
      printf("Error in reading mapfile\n");
      Close(file);
      return 1;
   }
   return 0;
}

int Random (int alaraja, int ylaraja) {
    int Luku;
    Luku=rand();
    Luku=alaraja+Luku%(ylaraja-alaraja);
    return Luku;
}
Advertisements

In my high school times I mostly listened to Amiga music and C64 music rather than ”real” music. I will now take a look back in time to some of the best Amiga modules I listened to.

Spell Amelioration from Uncle Tom was one of my favorites. Personal and technically good ProTracker music module.

Also Poseidon from Uncle Tom was one of my favorites.

Of course Klisje paa klisje was a real good tune to listen to:

Jogeir Liljedahl’s Face Another Day had big enlightening impact on me:

Many chip tunes on Amiga really touched me. Below is a compilation of some of the most famous chip tunes including many of my favorites:

Many people have been touched by good Amiga music and remixed their favorite tunes with synthesizers and real instruments.

Below is my own so called chip tune made with OctaMED on Amiga:

Some of the Amiga musicians have become professonal musicians.

If you’ve had C64 and/or Amiga childhood and/or youth this was probably good nostalgic trip to you too.


For example on Commodore 64 one can use absolute memory addresses somewhat freely; it is sufficient to know the memory map of C64. But on Amiga the case is completely different, because Amiga has multitasking operating system.

As it comes to allocating memory, even if one programs ”hard coded” program, that is: A program that overrides the operation of the operating system and use use directly Amiga’s hardware (Amiga has few co-processors), one can’t assume, that one can ”steal” memory anywhere one wants. In other words one can’t use absolute memory addressing and put one’s data anywhere one wants, because when the user closes the program, the whole multitasking environment can be ”broken”: There can be ”garbage” on the screen or some programs may have crashed, because the ”hard coded” program may have written its own data instead of the data on previously running programs in multitasking environment.

Still, on Amiga there is one absolute memory address, that every programmer in practice must use to get anything done when using the OS, namely address 4. From that memory address one gets so called execbase, that is necessary to call any system routines.

In order to make ”hard coded” program run faster on an Amiga it is practically necessary to stop the operation of the operating system (on an Amiga the OS routines are in ROM, though there are libraries, that are loaded (”opened” by the language of the programmer) to RAM that add more functionality to the OS). There are two ways to do that: To call OS’s Forbid() or Disable().

Image courtesy of jesadaphorn at FreeDigitalPhotos.net

Image courtesy of jesadaphorn at FreeDigitalPhotos.net

Using Forbid() is ”nice” way to stop the operation of the operating system, it forbids the task swapping of the OS, that is: All the programs on the background on the OS are stopped, until Wait() routine is called (or some of the Intuition library’s routines). Of course, when one codes “hard coded” program, one probably doesn’t use OS’s Wait(), but one’s own code using directly the hardware. When exiting ”hard coded” program, the programmer must now call Permit() in order to make the OS continue its tasks normally.

A way to get ”hard coded” program to run even faster, is to use Disable(), but that is quite naughty way to stop OS considering that the user may have a lot of programs and tasks running on the OS. Disable() stops the interruptions of the OS on the background, that is: The running of all the programs and also the interruption routines they may of their own are stopped.

Wait() routine allows interruptions regardless of Disable(), but returns the ”disabled state” after the CPU has finished the Wait() routine. Though, again in ”hard coded” programs, the programmer doesn’t probably use Wait(), but one’s own code to wait for something using directly the hardware.

If Disable() has been used, in the end of the program, one must use Enable() in order to get the OS functioning again. But if the programmer has used Disable(), there is no way to guarantee that even after Enable(), the OS is functioning normally as it was before executing the ”hard coded” program.

Still, there are some speed critical things or things where OS must be stopped for just a ”short” time on Amiga, where Disable() may be the only way to get a program working properly. Now, because Disable() ”forbids” interruption requests of the OS by setting Paula’s (a co-processor) INTENA register’s bit 14, it’s also a question of how long Disable() has stopped the OS; the longer the Disable() has stopped the OS, the more uncertain it is, that the OS is working completely – if at all – normally after Enable(). Usually the interruptions of the OS should not be stopped for over 250 microseconds at once.