【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】

想学好soc,再怎么看芯片手册和linux kernel都不为过。但是要学习好kernel,那再怎么看skyeye都不为过。学习虚拟机,不光可以自己添加soc,也可以自己添加外设硬件(比如网卡、norflash等等),实在不错。

我们自己可以找一段skyeye的soc代码,看看skyeye是怎么仿真外设的,比如1.2.5版本下对ep9312的仿真,

/*
	skyeye_mach_ep9312.c - define machine ep9312 for skyeye
	Copyright (C) 2003 Skyeye Develop Group
	for help please send mail to <skyeye-developer@lists.sf.linuxforum.net> 

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program; if not, write to the Free Software
	Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 

*/
/*
 * 11/06/2004	clean some codes
 *		wlm <wlm@student.dlut.edu.cn>
 * 10/8/2004 	init this file.
 * 		add machine ep9312's function.
 *		Cai Qiang <caiqiang@ustc.edu>
 *
 * */

#include "armdefs.h"
#include "clps9312.h"
#include "ep9312.h"
#include "serial_amba.h"
//zzc:2005-1-1
#ifdef __CYGWIN__
//chy 2005-07-28
#include <time.h>
//teawater add DBCT_TEST_SPEED 2005.10.04---------------------------------------
/*struct timeval
{
	int tv_sec;
	int tv_usec;
};*/
//AJ2D--------------------------------------------------------------------------
#endif

/* 2007-01-18 added by Anthony Lee : for new uart device frame */
#include "skyeye_uart.h"

void ep9312_io_write_word (ARMul_State * state, ARMword addr, ARMword data);
ARMword ep9312_io_read_word (ARMul_State * state, ARMword addr);

#define NR_UART			3

#define UART_FR_TXFE	(1<<7)
#define UART_FR_RXFE	(1<<4)

#define UART_IIR_RIS	(1<<1)
#define UART_IIR_TIS	(1<<2)

const int TCOI[2] = { 1 << 4, 1 << 5 };
const int UART_RXINTR[3] = { 1 << 23, 1 << 25, 1 << 27 };
const int UART_TXINTR[3] = { 1 << 24, 1 << 26, 1 << 28 };
const int INT_UART[3] = { 1 << (52 - 32), 1 << (54 - 32), 1 << (55 - 32) };
const int iConsole = 0;		//index of uart of serial console

/*Internal IO Register*/
typedef struct ep9312_io
{
	ARMword syscon_devcfg;	/* System control */

	ARMword intsr[2];	/* Interrupt status reg */
	ARMword intmr[2];	/* Interrupt mask reg */

	struct ep9312_tc_io tc[4];
	struct ep9312_uart_io uart[NR_UART];

} ep9312_io_t;

static ep9312_io_t ep9312_io;
#define io ep9312_io

static void
ep9312_update_int (ARMul_State * state)
{
	ARMword requests = io.intsr[0] & io.intmr[0];
	requests |= io.intsr[1] & io.intmr[1];

	state->NfiqSig = (requests & 0x0001) ? LOW : HIGH;
	state->NirqSig = (requests & 0xfffe) ? LOW : HIGH;
}

static void
ep9312_io_reset (ARMul_State * state)
{
	int i;
	io.syscon_devcfg = 0;
	io.intmr[0] = 0;
	io.intmr[1] = 0;

	/* reset TC register */
	io.tc[0].value = 0;
	io.tc[1].value = 0;
	io.tc[2].value = 0;
	io.tc[0].mod_value = 0xffff;
	io.tc[1].mod_value = 0xffff;
	io.tc[2].mod_value = 0xffffffff;

	for (i = 0; i < NR_UART; i++) {
		io.uart[i].dr = 0;
		io.uart[i].fr = UART_FR_TXFE;
	}
}

void
ep9312_io_do_cycle (ARMul_State * state)
{
	int i;

	/* We must implement TC1, TC2 and TC4 */
	for (i = 0; i < 2; i++) {
		if (io.tc[i].value == 0) {
			if (io.tc[i].ctl & TC_CTL_MODE)
				io.tc[i].value = io.tc[i].load;
			else
				io.tc[i].value = io.tc[i].mod_value;
			io.intsr[0] |= TCOI[i];
			ep9312_update_int (state);
		}
		else {
			io.tc[i].value--;
		}
	}
	io.tc[3].load++;

	if (!(io.intsr[0] & (UART_RXINTR[iConsole]))
	    && io.uart[iConsole].dr == 0) {
		/* 2007-01-18 modified by Anthony Lee : for new uart device frame */
		struct timeval tv;
		unsigned char buf;

		tv.tv_sec = 0;
		tv.tv_usec = 0;

		if(skyeye_uart_read(-1, &buf, 1, &tv, NULL) > 0)
		{
			io.uart[iConsole].dr = (int) buf;
			io.intsr[0] |= UART_RXINTR[iConsole];
			io.intmr[0] |= UART_RXINTR[iConsole];
			io.intsr[1] |= INT_UART[iConsole];
			io.intmr[1] |= INT_UART[iConsole];
			io.uart[iConsole].iir |= UART_IIR_RIS;
			io.uart[iConsole].fr &= ~UART_FR_RXFE;
			ep9312_update_int (state);
		}
	}			//if (!(io.intsr & URXINT))
}

static void
ep9312_uart_read (ARMul_State * state, u32 offset, u32 * data, int index)
{
	switch (offset) {
	case UART_DR:
		*data = io.uart[index].dr;
		io.uart[index].dr = 0;
		io.intsr[0] &= ~(UART_RXINTR[index]);
		io.intsr[1] &= ~(INT_UART[index]);
		io.uart[index].iir &= ~UART_IIR_RIS;
		io.uart[index].fr |= UART_FR_RXFE;
		ep9312_update_int (state);
		break;
	case UART_RSR:
		*data = io.uart[index].rsr;
		break;
		//case UART_ECR:
	case UART_CR_H:
	case UART_CR_M:
	case UART_CR_L:
		break;
	case UART_CR:
		*data = io.uart[index].cr;
		break;
	case UART_FR:
		*data = io.uart[index].fr;
		break;
	case UART_IIR:
		*data = io.uart[index].iir;
		break;
		//case UART_ICR:
	case UART_ILPR:
	case UART_DMACR:
	case UART_TCR:
	case UART_TISR:
	case UART_TOCR:
	case UART_TMR:
	case UART_MCR:
	case UART_MSR:
		break;
	default:
		SKYEYE_DBG ("%s(0x%x, 0x%x)\n", __func__, offset, data);
		break;
	}
}
static void
ep9312_uart_write (ARMul_State * state, u32 offset, u32 data, int index)
{
	switch (offset) {
	case UART_DR:
		{
			char c = data;

			/* 2007-01-18 modified by Anthony Lee : for new uart device frame */
			skyeye_uart_write(-1, &c, 1, NULL);
		}
	case UART_RSR:
		//case UART_ECR:
	case UART_CR_H:
	case UART_CR_M:
	case UART_CR_L:
		break;
	case UART_CR:
		{
			io.uart[index].cr = data;
			if ((data & AMBA_UARTCR_TIE) == 0) {
				io.intmr[0] &= ~(UART_TXINTR[index]);
				io.intsr[0] &= ~(UART_TXINTR[index]);
				io.intsr[1] &= ~(INT_UART[index]);
				io.intmr[1] &= ~(INT_UART[index]);

				io.uart[index].iir &= ~(UART_IIR_TIS);	//Interrupt Identification and Clear
			}
			else {

				io.intmr[0] |= (UART_TXINTR[index]);
				io.intsr[0] |= (UART_TXINTR[index]);
				io.intsr[1] = (INT_UART[index]);
				io.intmr[1] = (INT_UART[index]);
				io.uart[index].iir |= (UART_IIR_TIS);
			}
			ep9312_update_int (state);
		}
		break;
	case UART_FR:
	case UART_IIR:
		io.uart[index].iir = data;
		break;
		//case UART_ICR:
	case UART_ILPR:
	case UART_DMACR:
	case UART_TCR:
	case UART_TISR:
	case UART_TOCR:
	case UART_TMR:
	case UART_MCR:
	case UART_MSR:
		break;
	default:
		SKYEYE_DBG ("%s(0x%x, 0x%x)\n", __func__, offset, data);
	}
}

/* Timer read/write register
 */
static void
ep9312_tc_read (u32 offset, u32 * data, int index)
{
	if (index == 4) {
		if (offset == TC_VALUELOW)
			*data = io.tc[index].load;
		else if (offset == TC_VALUEHIGH)
			*data = io.tc[index].value;
	}
	switch (offset) {
	case TC_LOAD:
		*data = io.tc[index].load;
		break;
	case TC_VALUE:
		*data = io.tc[index].value;
		break;
	case TC_CTL:
		*data = io.tc[index].ctl;
		break;
	case TC_CLEAR:
		SKYEYE_DBG ("%s(0x%x, 0x%x): read WO register\n", __func__,
			    offset, data);
		break;
	default:
		SKYEYE_DBG ("%s(0x%x, 0x%x)\n", __func__, offset, data);
		break;
	}
}
static void
ep9312_tc_write (ARMul_State * state, u32 offset, u32 data, int index)
{
	switch (offset) {
	case TC_LOAD:
		io.tc[index].load = data;
		break;
	case TC_VALUE:
		SKYEYE_DBG ("%s(0x%x, 0x%x): write RO register\n", __func__,
			    offset, data);
		break;
	case TC_CTL:
		io.tc[index].ctl = data;
		break;
	case TC_CLEAR:
		io.intsr[0] &= ~TCOI[index];
		ep9312_update_int (state);
		break;
	default:
		SKYEYE_DBG ("%s(0x%x, 0x%x)\n", __func__, offset, data);
		break;
	}
}

ARMword
ep9312_io_read_byte (ARMul_State * state, ARMword addr)
{
	return ep9312_io_read_word (state, addr);
}

ARMword
ep9312_io_read_halfword (ARMul_State * state, ARMword addr)
{

	SKYEYE_DBG ("SKYEYE: %s error\n", __func__);
}

ARMword
ep9312_io_read_word (ARMul_State * state, ARMword addr)
{
	ARMword data = 0;

	/* TC1 */
	if ((addr >= EP9312_TC_BASE1) &&
	    (addr < (EP9312_TC_BASE1 + EP9312_TC_SIZE))) {
		ep9312_tc_read ((u32) (addr - EP9312_TC_BASE1),
				(u32 *) & data, 0);
	}
	/* TC2 */
	if ((addr >= EP9312_TC_BASE4) &&
	    (addr < (EP9312_TC_BASE4 + EP9312_TC_SIZE))) {
		ep9312_tc_read ((u32) (addr - EP9312_TC_BASE4),
				(u32 *) & data, 3);
	}
	/* UART1 */
	if ((addr >= EP9312_UART_BASE1) &&
	    (addr < (EP9312_UART_BASE1 + EP9312_UART_SIZE))) {
		ep9312_uart_read (state, (u32) (addr - EP9312_UART_BASE1),
				  (u32 *) & data, 0);
		return data;
	}
	/* UART3 */
	if ((addr >= EP9312_UART_BASE3) &&
	    (addr < (EP9312_UART_BASE3 + EP9312_UART_SIZE))) {
		ep9312_uart_read (state, (u32) (addr - EP9312_UART_BASE3),
				  (u32 *) & data, 2);
		return data;
	}
	switch (addr) {
	case SYSCON_PWRCNT:
		break;
	case VIC0INTENABLE:
		data = io.intmr[0];
//              printf("%s(0x%08x) = 0x%08x\n", __func__, addr, data);
		break;
	case VIC0IRQSTATUS:
		data = io.intsr[0];
		io.intsr[0] = 0;	//!!!
		break;
	case VIC1IRQSTATUS:
		data = io.intsr[1];
		io.intsr[1] = 0;
		break;
	case RTCDR:
	case AACGCR:
	case AACRGIS:
//              printf("%s(0x%08x) = 0x%08x\n", __func__, addr, data);
		break;
	case SYSCON_DEVCFG:
		data = io.syscon_devcfg;
		break;
	default:
		SKYEYE_DBG ("SKYEYE:unknown io addr, %s(0x%08x) = 0x%08x\n",
			    __func__, addr, data);
		break;
	}
	return data;
}

void
ep9312_io_write_byte (ARMul_State * state, ARMword addr, ARMword data)
{
	ep9312_io_write_word (state, addr, data);
}

void
ep9312_io_write_halfword (ARMul_State * state, ARMword addr, ARMword data)
{
	SKYEYE_DBG ("SKYEYE: %s error\n", __func__);
}

void
ep9312_io_write_word (ARMul_State * state, ARMword addr, ARMword data)
{
	ARMword tmp;
	if ((addr >= EP9312_TC_BASE1) &&
	    (addr < (EP9312_TC_BASE1 + EP9312_TC_SIZE))) {
		ep9312_tc_write (state, (u32) (addr - EP9312_TC_BASE1), data,
				 0);
	}
	if ((addr >= EP9312_UART_BASE1) &&
	    (addr < (EP9312_UART_BASE1 + EP9312_UART_SIZE))) {
		ep9312_uart_write (state, (u32) (addr - EP9312_UART_BASE1),
				   data, 0);
	}
	if ((addr >= EP9312_UART_BASE3) &&
	    (addr < (EP9312_UART_BASE3 + EP9312_UART_SIZE))) {
		ep9312_uart_write (state, (u32) (addr - EP9312_UART_BASE3),
				   data, 2);
	}

	switch (addr) {
	case SYSCON_CLKSET1:
		break;
	case SYSCON_CLKSET2:
	case SYSCON_PWRCNT:
		break;
	case VIC0INTENABLE:
		io.intmr[0] = data;
		if (data != 0x10 && data != 0x20)
			printf ("SKYEYE: write VIC0INTENABLE=0x%x\n", data);
		ep9312_update_int (state);
		break;
	case VIC1INTENABLE:
		io.intmr[1] = data;
//              printf("SKYEYE: write VIC1INTENABLE=0x%x\n", data);

		ep9312_update_int (state);
		break;
	case VIC0INTENCLEAR:
		io.intmr[0] ^= data;
		ep9312_update_int (state);
		break;
	case VIC1INTENCLEAR:
		io.intmr[1] ^= data;
		ep9312_update_int (state);
		break;
	case SYSCON_DEVCFG:
		io.syscon_devcfg = data;
		break;
	default:
		SKYEYE_DBG
			("SKYEYE:unknown io addr, %s(0x%08x, 0x%08x), pc %x \n",
			 __func__, addr, data, state->Reg[15]);
		break;
	}
}

void
ep9312_mach_init (ARMul_State * state, machine_config_t * this_mach)
{
	ARMul_SelectProcessor (state, ARM_v4_Prop);
	/* ARM920T uses LOW */
	state->lateabtSig = LOW;

//      state->Reg[1] = 282;    //for EP9312 2.4.x arch id
	state->Reg[1] = 451;	//for EP9312 2.6.x arch id
	//state->Reg[1] = 386;  //for EP9315 2.4.x arch id
	this_mach->mach_io_do_cycle = ep9312_io_do_cycle;
	this_mach->mach_io_reset = ep9312_io_reset;
	this_mach->mach_io_read_byte = ep9312_io_read_byte;
	this_mach->mach_io_write_byte = ep9312_io_write_byte;
	this_mach->mach_io_read_halfword = ep9312_io_read_halfword;
	this_mach->mach_io_write_halfword = ep9312_io_write_halfword;
	this_mach->mach_io_read_word = ep9312_io_read_word;
	this_mach->mach_io_write_word = ep9312_io_write_word;

	this_mach->mach_update_int = ep9312_update_int;

}

我觉得soc仿真的意义在于让外设的地址读写变得有意义,比如如何让串口地址进行输出、让时钟进行计数、让中断可以真正地发挥作用。上面这段代码看上去行数很多,但是最重要的还是最后一个函数。当然,除此之外,系统注册也是必不可少的,

machine_config_t arm_machines[] = {
	/* machine define for cpu without mmu */
	{"at91", at91_mach_init, NULL, NULL, NULL},		/* ATMEL AT91X40 */
	{"lpc", lpc_mach_init, NULL, NULL, NULL},		/* PHILIPS LPC2xxxx */
	{"s3c4510b", s3c4510b_mach_init, NULL, NULL, NULL},	/* Samsung s3c4510b */
	{"s3c44b0x", s3c44b0x_mach_init, NULL, NULL, NULL},	/* Samsung s3c44b0x */
	{"s3c44b0", s3c44b0x_mach_init, NULL, NULL, NULL},	/* Samsung s3c44b0x */
	{"s3c3410x", s3c3410x_mach_init, NULL, NULL, NULL},	/* Samsung s3c3410x */

	/* machine define for cpu with mmu */
	{"ep7312", ep7312_mach_init, NULL, NULL, NULL},		/* Cirrus Logic EP7312 */
	{"lh79520", lh79520_mach_init, NULL, NULL, NULL},	/* sharp LH79520 */
	{"ep9312", ep9312_mach_init, NULL, NULL, NULL},		/* Cirrus Logic EP9312 */
	{"cs89712", cs89712_mach_init, NULL, NULL, NULL},	/* cs89712 */
	{"sa1100", sa1100_mach_init, NULL, NULL, NULL},		/* sa1100 */
	{"pxa_lubbock", pxa250_mach_init, NULL, NULL, NULL},	/* xscale pxa250 lubbock developboard */
	{"pxa_mainstone", pxa270_mach_init, NULL, NULL, NULL},	/* xscale pxa270 mainstone developboard */
	{"at91rm92", at91rm92_mach_init, NULL, NULL, NULL},	/* at91RM9200 */
	{"s3c2410x", s3c2410x_mach_init, NULL, NULL, NULL},	/* s3c2410x */
	{"s3c2440", s3c2440_mach_init, NULL, NULL, NULL},	/* s3c2440 */
	{"sharp_lh7a400", shp_mach_init, NULL, NULL, NULL},	/* sharp lh7a400 developboard */
	{"ns9750", ns9750_mach_init, NULL, NULL, NULL},		/* NetSilicon ns9750 */
	{"lpc2210", lpc2210_mach_init, NULL, NULL, NULL},	/* Philips LPC2210 */
	{"ps7500", ps7500_mach_init, NULL, NULL, NULL},		/* Cirrus Logic PS7500FE */
};

有了这两个文件,基本上soc的逻辑算是了解了。


随想录(skyeye中的soc仿真)的更多相关文章

  1. 全向轮运动学与V-rep中全向移动机器人仿真

    Wheeled mobile robots may be classified in two major categories, omnidirectional and nonholonomic. O ...

  2. 在ModelSim中添加Xilinx仿真库

    在ModelSim中添加Xilinx仿真库 说明: l ModelSim一定要安装在不带空格的目录下,即不要安装在“Program Files”目录下.如作者是安装在D:\softwares\Mode ...

  3. orcad中的PSpice仿真加入厂商模型

      <1>首先要知道原理图的符号是没有模型的,不是你肆意妄为就可以拉来仿真的. <2>其次要知道很多器件软件中是没有模型的. <3>有很多获取模型的方法:<使 ...

  4. [置顶] NS2中TCP拥塞控制仿真过程中盲点解析

    最近利用NS2做TCP拥塞控制协议的仿真,发现很多变量的方法含义都是解释的不清楚,给核心模块修改带来很多麻烦,所以决定用最准确的语言解释成员变量.方法,术语等的含义.限于个人水平,若有错误请留言指正! ...

  5. EETOP中关于Gm仿真的一些帖子的总结

    1. cadence画gm曲线 电路里,要把漏的电源dc值设置成变量,比如叫vds,计算器,info标签,点op,然后点管子,在op窗口点list,选gm,然后把这个公式弄到ADE的outputs那里 ...

  6. 在modelsim中加入quartus仿真库

    找到modelsim安装目录下的modelsim.ini文件. 将modelsim.ini的只读属性去掉. 打开quartus软件.选择Launch Simulation Library Compil ...

  7. 向modesim中添加alter库 (或者在每次仿真时将库文件加入仿真文件夹一起编译)

    在ModelSim中进行仿真需要加入Quartus提供的仿真库,原因是下面三个方面:    ·Quartus不支持Testbench:    ·调用了megafunction或者lpm库之类的Alte ...

  8. 【仿真】Lattice_Diamond_调用Modelsim_仿真

    仿真前的准备工作:在modelsim中添加lattice仿真库:1.去除modelsim安装目录下modelsim.ini的只读属性.2.打开modelsim,更改目录File>Change d ...

  9. [转]使用Cadence ADE + Spectre做Montel Carlo仿真

    1. 工艺模型的选择.以TSMC 180nm工艺为例,1.8V Normal devices 有TT,SS,FF,SF,FS共5种工艺Corner及Montel Carlo(MC)共6种可选用工艺角. ...

随机推荐

  1. python之路 堡垒机paramiko

    paramiko 1.安装 pip3 install paramiko 二.使用 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: import paramiko # 创建S ...

  2. CF335B

    /*CF335B 这个题目的n达到50000,但是串只是有小写字母组成,所以如果字符串的长度大于2600,那么 肯定存在,所开始输入就判断如果长度大于2600,那么直接找当个字母输出100个 否则执行 ...

  3. Linux:查看磁盘空间占用情况

    Linux:查看磁盘空间占用情况 工作中有时被分配的测试机空间不大,经常遇到磁盘空间占满的情况.排查过程如下: 一.首先使用df -h 命令查看磁盘剩余空间,通过以下图看出/目录下的磁盘空间已经被占满 ...

  4. 小技巧|使用Vue.js的Mixins复用你的代码

    Vue中的混入 mixins 是一种提供分发 Vue 组件中可复用功能的非常灵活的方式.听说在3.0版本中可能会用Hooks的形式实现,但这并不妨碍它的强大. 这里主要来讨论 mixins 如何优化我 ...

  5. CSS3自定义发光radiobox单选框

    在线演示 本地下载

  6. PHP面向对象程序设计之抽象类和抽象方法

    抽象类: 抽象类不能被实例化.抽象类中只定义(或部分实现)子类需要的方法.子类可以继承它并且通过实现其中的抽象方法,使抽象类具体化. 我们可以用一个abstract关键字来定义一个抽象类,示例如下: ...

  7. mysql一次性删除所有表而不删除数据库

    1.执行如下语句获取删除语句 SELECT CONCAT( 'drop table ', table_name, ';' ) from information_schema.tables where ...

  8. NumPy切片和索引

    NumPy - 切片和索引 ndarray对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样. 如前所述,ndarray对象中的元素遵循基于零的索引. 有三种可用的索引方 ...

  9. scala学习手记37 - 容器的使用

    这次统一看一下scala中容器类的几个方法. Set filter()方法 filter()方法用来从Set中过滤获取含有指定特征的元素.示例代码如下: val colors1 = Set(" ...

  10. JNI_Z_10_Java的数组

    在Java中数组分为两种: (1).基本类型数组 (2).对象类型(Object[])的数组 (数组中存放的是指向Java对象中的引用) 一个能通用于两种不同类型数组的函数: GetArrayLeng ...