随想录(skyeye中的soc仿真)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱: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仿真)的更多相关文章
- 全向轮运动学与V-rep中全向移动机器人仿真
Wheeled mobile robots may be classified in two major categories, omnidirectional and nonholonomic. O ...
- 在ModelSim中添加Xilinx仿真库
在ModelSim中添加Xilinx仿真库 说明: l ModelSim一定要安装在不带空格的目录下,即不要安装在“Program Files”目录下.如作者是安装在D:\softwares\Mode ...
- orcad中的PSpice仿真加入厂商模型
<1>首先要知道原理图的符号是没有模型的,不是你肆意妄为就可以拉来仿真的. <2>其次要知道很多器件软件中是没有模型的. <3>有很多获取模型的方法:<使 ...
- [置顶] NS2中TCP拥塞控制仿真过程中盲点解析
最近利用NS2做TCP拥塞控制协议的仿真,发现很多变量的方法含义都是解释的不清楚,给核心模块修改带来很多麻烦,所以决定用最准确的语言解释成员变量.方法,术语等的含义.限于个人水平,若有错误请留言指正! ...
- EETOP中关于Gm仿真的一些帖子的总结
1. cadence画gm曲线 电路里,要把漏的电源dc值设置成变量,比如叫vds,计算器,info标签,点op,然后点管子,在op窗口点list,选gm,然后把这个公式弄到ADE的outputs那里 ...
- 在modelsim中加入quartus仿真库
找到modelsim安装目录下的modelsim.ini文件. 将modelsim.ini的只读属性去掉. 打开quartus软件.选择Launch Simulation Library Compil ...
- 向modesim中添加alter库 (或者在每次仿真时将库文件加入仿真文件夹一起编译)
在ModelSim中进行仿真需要加入Quartus提供的仿真库,原因是下面三个方面: ·Quartus不支持Testbench: ·调用了megafunction或者lpm库之类的Alte ...
- 【仿真】Lattice_Diamond_调用Modelsim_仿真
仿真前的准备工作:在modelsim中添加lattice仿真库:1.去除modelsim安装目录下modelsim.ini的只读属性.2.打开modelsim,更改目录File>Change d ...
- [转]使用Cadence ADE + Spectre做Montel Carlo仿真
1. 工艺模型的选择.以TSMC 180nm工艺为例,1.8V Normal devices 有TT,SS,FF,SF,FS共5种工艺Corner及Montel Carlo(MC)共6种可选用工艺角. ...
随机推荐
- python之路 堡垒机paramiko
paramiko 1.安装 pip3 install paramiko 二.使用 SSHClient 用于连接远程服务器并执行基本命令 基于用户名密码连接: import paramiko # 创建S ...
- CF335B
/*CF335B 这个题目的n达到50000,但是串只是有小写字母组成,所以如果字符串的长度大于2600,那么 肯定存在,所开始输入就判断如果长度大于2600,那么直接找当个字母输出100个 否则执行 ...
- Linux:查看磁盘空间占用情况
Linux:查看磁盘空间占用情况 工作中有时被分配的测试机空间不大,经常遇到磁盘空间占满的情况.排查过程如下: 一.首先使用df -h 命令查看磁盘剩余空间,通过以下图看出/目录下的磁盘空间已经被占满 ...
- 小技巧|使用Vue.js的Mixins复用你的代码
Vue中的混入 mixins 是一种提供分发 Vue 组件中可复用功能的非常灵活的方式.听说在3.0版本中可能会用Hooks的形式实现,但这并不妨碍它的强大. 这里主要来讨论 mixins 如何优化我 ...
- CSS3自定义发光radiobox单选框
在线演示 本地下载
- PHP面向对象程序设计之抽象类和抽象方法
抽象类: 抽象类不能被实例化.抽象类中只定义(或部分实现)子类需要的方法.子类可以继承它并且通过实现其中的抽象方法,使抽象类具体化. 我们可以用一个abstract关键字来定义一个抽象类,示例如下: ...
- mysql一次性删除所有表而不删除数据库
1.执行如下语句获取删除语句 SELECT CONCAT( 'drop table ', table_name, ';' ) from information_schema.tables where ...
- NumPy切片和索引
NumPy - 切片和索引 ndarray对象的内容可以通过索引或切片来访问和修改,就像 Python 的内置容器对象一样. 如前所述,ndarray对象中的元素遵循基于零的索引. 有三种可用的索引方 ...
- scala学习手记37 - 容器的使用
这次统一看一下scala中容器类的几个方法. Set filter()方法 filter()方法用来从Set中过滤获取含有指定特征的元素.示例代码如下: val colors1 = Set(" ...
- JNI_Z_10_Java的数组
在Java中数组分为两种: (1).基本类型数组 (2).对象类型(Object[])的数组 (数组中存放的是指向Java对象中的引用) 一个能通用于两种不同类型数组的函数: GetArrayLeng ...