⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 arm_00_os_core.c

📁 看看ARM菜鸟在ARM7上写的操作系统——ARM圈圈操作系统 最近在ADuC7027上写了一个ARM_00_OS
💻 C
📖 第 1 页 / 共 4 页
字号:
/**********************************************************************************************
本程序只供学习使用,不得用于其它任何用途,否则后果自负。

  ARM_00_OS_Core.c file
   
  作者:Computer-lov
  建立日期:2006-5-1
  修改日期:2006-5-15
  版本:V1.0
  版权所有,盗版必究。
  任何技术问题可到我的博客上留言:    http://computer00.21ic.org
  Copyright(C) Computer-lov 2006-2016
  All rights reserved
**********************************************************************************************/

#include <ADuC7027.H>

#include "interrupt.h"
#include "LED.H"
#include "ARM_00_OS_TaskSwitch.H"
#include "my_type.h"
#include "ARM_00_OS_Core.H"
#include "UART.H"
#include "KEYS.H"
#include "Task.h"

OSpcb * OSReadyList;    //就绪态任务表表头
OSpcb * OSSuspendList;  //挂起态任务表表头
OSpcb * OSDelayList;    //延时态任务表表头
OSpcb * OSCurrentPcb;   //当前运行的任务


OSpcb OSSystemIdlePcb;  //系统空闲任务
OSShortPcb OSSuspendListBottom;    //挂起态列表表底
OSShortPcb OSDelayListBottom;      //延时态列表表底 


OSdevice OSDeviceBottom;       //设备列表的底部
OSdevice * OSDeviceList;       //设备列表


volatile uint32 CopyOfIRQEN;    //用来备份IRQEN的状态
volatile uint32 CopyOfFIQEN;    //用来备份FIQEN的状态
volatile uint32 OSEnCrCount;    //用来统计进入临界代码段次数


volatile uint32 TaskAmount;    //用来统计共有多少个任务


volatile uint32 TimeOfTaskStart;  //用来保存一个任务刚被切换到运行态的时刻

#define OSMemoryLack       0x0000000100000000  /*错误号:内存资源不足*/

/**********************************************************************************************
功能:内存管理。
入口参数1:Operation。操作方式。可以设置为MEMORY_ALLOCATION(分配)、MEMORY_FREE(释放)、统计使用量(MEMORY_STATISTIC)
入口参数2:StartAddr。起始地址,释放内存时使用。
入口参数3:Length。申请内存或释放内存时的长度,单位为字节。但实际分配时,是按块分配的,所以分配时,
           实际分配到的数量可能会比指定的多,所以分配时,最好按块的整数倍大小来指定分配长度。
		   
返回:32无符号型整数。
      当操作为分配内存时,返回32位的内存首地址,返回0表示无足够多的可以用内存。
      当操作为释放内存时,返回1表示释放成功。返回0表示释放出错。
	  当操作为统计内存使用量时,返回的是内存被使用的字节数。
      当操作为获取缓冲池大小时,返回的是内存缓冲池大小。

备注:缓冲池大小由OSSizeOfMemoryPool指定。每块的大小由OSSizePerBlock指定             
**********************************************************************************************/
uint32 OSMemoryManage(uint32 Operation,uint32 StartAddr,uint32 Length)
{
  //内存分配表
  //内存分配表是32位整数的一维数组。用每一位来表示一块是否被使用。当某位设置为1时,表示那一块被使用。
  //当某位为0时,表示那一块可用。
 static uint32  OSMemoryTable[OSSizeOfMemoryPool/OSSizePerBlock/32];
                                                                      
 static uint32 OSMemoryPool[OSSizeOfMemoryPool/4]; //内存缓冲池。内存缓冲池为一个大是数组
 
 uint32 BlankCount;    //统计空块的计数器
 uint32 Mask;          //分配内存时用的掩码
 volatile uint32 i,j;  //循环用的变量

 OSEnterCritical();   //进入临界段
 
 switch(Operation)     //根据操作码,选择不同的操作
  {
   case MEMORY_INIT:   //如果是内存初始化
    {
     for(i=0;i<OSSizeOfMemoryPool/OSSizePerBlock/32;i++)
      {
       OSMemoryTable[i]=0;  //则将整张内存分配表清0
      }
     OSExitCritical();  //退出临界段
     return 1;   //返回1
    }

   case MEMORY_ALLOCATION:  //如果是内存分配,则
    {
     BlankCount=0;   //先将内存空块的数量清0
     for(i=0;i<(OSSizeOfMemoryPool/OSSizePerBlock/32);i++)  //扫描整个内存分配表
      {
       Mask=1;   //掩码被设置为1,即最低位为1,其它位为0。
       if(OSMemoryTable[i]==0xFFFFFFFF)  //如果该字中的所以位都为1,表示该字节对应的所有块都被占用
        {
         BlankCount=0;  //空块计数器置0
         continue;      //退出本次循环,查找下一个字
        }
       for(j=0;j<32;j++)  //扫描一个字的32个bit是否有空闲的RAM
        {
         if((Mask & OSMemoryTable[i])==0)  //如果该位为0,表示该块空闲
          {
           BlankCount++;   //空块计数器加1。
          }
         else
          {
           BlankCount=0;  //如果遇到非空块,则空块计数器置0。
          }
         if((BlankCount*OSSizePerBlock)>=Length)  //如果空闲的RAM,大于或者等于需要的长度,那么分配成功
          {
           //计算被分配到的内存的起始地址,并将其保存在StartAddr中。
           StartAddr=((uint32)OSMemoryPool)+(i*32+j+1)*OSSizePerBlock-OSSizePerBlock*BlankCount;
           while(1)  //设置被使用的块为1
            {
             OSMemoryTable[i] |=Mask;  //将已经被分配的标志为1
             Mask>>=1;   //调整掩码的值
             if(j==0)   //如果已到最低位
              {
               Mask=0x80000000; //则掩码调整为第31位为1
               j=32;
               i--;  //移到下一位
              }
             BlankCount--;  //空块计数减1
             j--;   //移到下一个字
             if(BlankCount==0)  //如果空块计数器减到0,则标志完毕
              {
               OSExitCritical();
               return StartAddr;   //将启始地址StartAddr返回
              }
            }
          }
         Mask<<=1;  //掩码调整,移动到下一个块
        }
      }
     OSExitCritical();
     return 0;  //如果没有足够大的内存块可用,则返回0,分配失败
    }

   case MEMORY_FREE:  //如果操作码是释放内存
    {
     if(Length==0)   //如果要释放的内存长度为0 
      {
       OSExitCritical();  //退出临界段
       return 1;    //返回1,释放成功
      }
     i=(StartAddr-(uint32)OSMemoryPool)/(32*OSSizePerBlock);   //计算出指定地址内存在内存分配表中的位置
     j=(StartAddr-(uint32)OSMemoryPool-i*32*OSSizePerBlock)/OSSizePerBlock;
     Mask=1<<j;   //将掩码调整到对应的值
     while(Length)  //直到全部被释放为止
      {
       if((OSMemoryTable[i])&(Mask)==0)   //如果该内存并未被分配,则说明发生了错误,
        {
         OSExitCritical();  //推出临界段
         return 0;      //返回0,表示释放失败
        }
       OSMemoryTable[i] &=~Mask;  //清除对应的位,即释放该块内存
       j++;      //调整到下一块
       Mask<<=1;   //掩码调整到下一块的位置
       if(j==32)  //如果已经到最高位
        {
         Mask=1;  //掩码设置为1
         j=0;    //j回到最低位
         i++;    //调整下一个字
        }
       if(Length<=OSSizePerBlock)  //如果释放完毕
        {
         Length=0;  //则Length设置为0,退出循环
        }
       else  //如果没释放完毕
        {
         Length-=OSSizePerBlock;  //则长度减小一个块的量
        }
      }
     OSExitCritical();  //退出临界段
     return 1;  //返回1,表示释放成功
    }

   case MEMORY_STATISTIC:  //如果操作码是统计内存使用量
    {
     Length=0;  //清Length
     for(i=0;i<OSSizeOfMemoryPool/OSSizePerBlock/32;i++)   //扫描整张内存分配表
      {
       if(OSMemoryTable[i]==0)    //如果当前字是全0,则该字对应的内存都未被分配,
        {
         continue;   //则跳过本次循环
        }
       if(OSMemoryTable[i]==0xFFFFFFFF)   //如果当前字是全1,则该字对应的内存全部被分配
        {
         Length+=32*OSSizePerBlock;   //Length累加上32块的长度
         continue;  //退出本次循环
        }
       Mask=1;   //掩码设置为1
       for(j=0;j<32;j++)  //扫描当前字的32bit,看是否有内存被使用
        {
         if(OSMemoryTable[i]&Mask)  //如果该块被使用
          {
           Length+=OSSizePerBlock;  //则Length累加一块的长度
          }
         Mask<<=1;  //调整掩码到下一位
        }
      }
     OSExitCritical();  //退出临界段
     return Length;   //返回使用的内存数量
    }

   case GET_MEMORY_POOL_SIZE:  //如果是获取缓冲池大小,
    {
     OSExitCritical();  //退出临界段
     return OSSizeOfMemoryPool;  //返回缓冲池的字节数
    }

   case MEMORY_TEST:  //如果是内存检测
    {
     j=0xFF;  //标志j为非0,即初始化成功
     prints("Memory testing. ",1);  //显示信息
     for(i=0;i<OSSizeOfMemoryPool/4;i++)  //检测整个内存缓冲池
      {
       OSMemoryPool[i]=0x55555555;   //写入0x55555555
       if(OSMemoryPool[i]!=0x55555555)  //如果读回的不是0x55555555
        {
         j=0;  //则测试失败
        }
       OSMemoryPool[i]=0xAAAAAAAA;   //写入0xAAAAAAAA
       if(OSMemoryPool[i]!=0xAAAAAAAA)  //如果读回的不是0xAAAAAAAA
        {
         j=0;  //则测试失败
        }
       OSMemoryPool[i]=0;   //写入0
       if(OSMemoryPool[i]!=0)  //如果读回的不是0
        {
         j=0;  //则测试失败
        }
       if(i%(OSSizeOfMemoryPool/4/80)==0)  //显示测试进度。共显示80个>
        {
         prints(">",0);
        }
      }
     prints("",1);
     if(j)  //如果测试成功
      {
       prints("Memory test passed.",1);  //显示成功
      }
     else  //否则,
      {
       prints("Memroy test failed.",1);  //显示测试失败
      }
     OSExitCritical();  //退出临界段
     return j;  //返回是否成功
    }
   default: OSExitCritical();return 0;
  }
}
//////////////////////////////////End of function//////////////////////////////////////////////


/**********************************************************************************************
功能:进入临界段。
入口参数:无。
返回:无。
备注:该函数使用的是将中断分配寄存器清0的方法来关中断。比起用软中断,运行速度要快。
      如果要开某个中断,则应该先调用一次该函数,然后再修改中断备份变量CopyOfIRQEN跟CopyOfFIQEN
	  的值,而不能直接修改IRQEN跟FIQEN的值。否则会出错。
**********************************************************************************************/
void OSEnterCritical(void)
{
 if(OSEnCrCount==0)   //如果前面未关中断

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -