本文来自《自己动手写cpu》一书的总结。原来自己看过原作者的《步步惊芯--软核处理器分析》以及其他关于or1200的书。本次粗略浏览了该书,就某些感兴趣的部分详细分析,并总结成此文。

关于5级流水的架构,可以自己去参考《计算机接口》一书。本文重点不在此。


1、如何从rom里面取地址

简化版的最基本的sopc的框图如下:

module openmips(input    wire            clk,input wire          rst,     input wire[`RegBus]           rom_data_i,output wire[`RegBus]           rom_addr_o,output wire                    rom_ce_o
);
always @ (posedge clk) beginif (ce == `ChipDisable) beginpc <= 32'h00000000;end else beginpc <= pc + 4'h4;endendalways @ (posedge clk) beginif (rst == `RstEnable) begince <= `ChipDisable;end else begince <= `ChipEnable;endend
 input wire[`InstAddrBus]      if_pc,input wire[`InstBus]          if_inst,output reg[`InstAddrBus]      id_pc,output reg[`InstBus]          id_inst  always @ (posedge clk) beginif (rst == `RstEnable) beginid_pc <= `ZeroWord;id_inst <= `ZeroWord;end else beginid_pc <= if_pc;id_inst <= if_inst;endend

可以看到以上3个代码段,第一段是openmips中的,表示怎么连接含有指令的rom,第二段是pc_reg.v中的,pc是自加的,然后一直是可以对rom取址的,第3段是if_id.v中的,可以看到取址后传递给了译码模块。这就是最基本的程序跑起来的开始。

后面作者自己收东西写指令码实现了与寄存器s0的操作,按照$readmemh的要求写成 inst_rom.data。inst_rom.v中读入了该文件。可以参考$readmemh的语法。

2、协处理器的概念:

比如说这里的定时器中断时间就应该很有用。

3、异常相关指令的实现

这里的定时器中断设置,是自己去写的汇编代码,然后验证指令正确。实际上我们一般是用c语言去写程序,编译器生成汇编代码和机器码。所以这些异常指令实际上应该是编译器去生产的,异常程序入口地址也不是我们操心的。但是这里我们只能自己写了。

4、wishbone总线:

说明:根据上面那个图,可以看到哈佛结构的指令rom和数据ram,都是例化了wishbone接口,均采用点对点的方式,连接到外部的有同样wishbone接口的rom和ram中。由于只是采用了这种接口协议,针对具体的情况还得在中间再加上一层接口模块,即上图所示的状态机,一部分是控制状态转化的时序电路,另一部分是给处理器接口信号赋值的组合电路。

module openmips(input    wire              clk,input wire              rst,  input wire[5:0]               int_i,//指令wishbone总线input wire[`RegBus]           iwishbone_data_i,input wire                    iwishbone_ack_i,output wire[`RegBus]           iwishbone_addr_o,output wire[`RegBus]           iwishbone_data_o,output wire                    iwishbone_we_o,output wire[3:0]               iwishbone_sel_o,output wire                    iwishbone_stb_o,output wire                    iwishbone_cyc_o, //数据wishbone总线input wire[`RegBus]           dwishbone_data_i,input wire                    dwishbone_ack_i,output wire[`RegBus]           dwishbone_addr_o,output wire[`RegBus]           dwishbone_data_o,output wire                    dwishbone_we_o,output wire[3:0]               dwishbone_sel_o,output wire                    dwishbone_stb_o,output wire                    dwishbone_cyc_o,output wire                    timer_int_o
);
wishbone_bus_if dwishbone_bus_if(.clk(clk),.rst(rst),//来自控制模块ctrl.stall_i(stall),.flush_i(flush),//CPU侧读写操作信息.cpu_ce_i(ram_ce_o),.cpu_data_i(ram_data_o),.cpu_addr_i(ram_addr_o),.cpu_we_i(ram_we_o),.cpu_sel_i(ram_sel_o),.cpu_data_o(ram_data_i),//Wishbone总线侧接口.wishbone_data_i(dwishbone_data_i),.wishbone_ack_i(dwishbone_ack_i),.wishbone_addr_o(dwishbone_addr_o),.wishbone_data_o(dwishbone_data_o),.wishbone_we_o(dwishbone_we_o),.wishbone_sel_o(dwishbone_sel_o),.wishbone_stb_o(dwishbone_stb_o),.wishbone_cyc_o(dwishbone_cyc_o),.stallreq(stallreq_from_mem)
);wishbone_bus_if iwishbone_bus_if(.clk(clk),.rst(rst),//来自控制模块ctrl.stall_i(stall),.flush_i(flush),//CPU侧读写操作信息.cpu_ce_i(rom_ce),.cpu_data_i(32'h00000000),.cpu_addr_i(pc),.cpu_we_i(1'b0),.cpu_sel_i(4'b1111),.cpu_data_o(inst_i),//Wishbone总线侧接口.wishbone_data_i(iwishbone_data_i),.wishbone_ack_i(iwishbone_ack_i),.wishbone_addr_o(iwishbone_addr_o),.wishbone_data_o(iwishbone_data_o),.wishbone_we_o(iwishbone_we_o),.wishbone_sel_o(iwishbone_sel_o),.wishbone_stb_o(iwishbone_stb_o),.wishbone_cyc_o(iwishbone_cyc_o),.stallreq(stallreq_from_if)
);

该章节源代码并没有给出有wishbone接口的rom和ram的源代码,但是从第一段的代码中可以看到实际上是要接有这么一种接口的rom和ram的。第二段代码可以看到分别实现了指令和数据的wb接口控制模块,直接接到外面的ram和rom。


5、小型的SOPC

module openmips_min_sopc(input   wire            clk,input wire          rst,    
        //新增uart接口input wire                   uart_in,output wire                   uart_out,//16位GPIO输入接口input wire[15:0]             gpio_i,
</pre><pre code_snippet_id="1671506" snippet_file_name="blog_20160504_9_3260604" name="code" class="plain">        //32位GPIO输出接口output wire[31:0]            gpio_o,
 //flash接口input wire[7:0]             flash_data_i,output wire[21:0]           flash_addr_o,output wire                 flash_we_o,output wire                 flash_rst_o,output wire                 flash_oe_o,output wire                 flash_ce_o,  
<span style="font-family: Arial, Helvetica, sans-serif;">                 //sdrsm接口</span>
 output wire sdr_clk_o,output wire sdr_cs_n_o,output wire sdr_cke_o,output wire sdr_ras_n_o,output wire sdr_cas_n_o,output wire sdr_we_n_o,output wire[1:0] sdr_dqm_o,output wire[1:0] sdr_ba_o,output wire[12:0] sdr_addr_o,inout wire[15:0] sdr_dq_io
);
 openmips openmips0(.clk(clk),.rst(rst),// 指令wb总线接口连到wb总线互联矩阵的主设备接口1.iwishbone_data_i(m1_data_o),.iwishbone_ack_i(m1_ack_o),.iwishbone_addr_o(m1_addr_i),.iwishbone_data_o(m1_data_i),.iwishbone_we_o(m1_we_i),.iwishbone_sel_o(m1_sel_i),.iwishbone_stb_o(m1_stb_i),.iwishbone_cyc_o(m1_cyc_i), .int_i(int),// 数据wb总线接口连到wb总线互联矩阵的主设备接口0.dwishbone_data_i(m0_data_o),.dwishbone_ack_i(m0_ack_o),.dwishbone_addr_o(m0_addr_i),.dwishbone_data_o(m0_data_i),.dwishbone_we_o(m0_we_i),.dwishbone_sel_o(m0_sel_i),.dwishbone_stb_o(m0_stb_i),.dwishbone_cyc_o(m0_cyc_i),.timer_int_o(timer_int) );// GPIO连到wb总线互联矩阵的从设备接口2gpio_top gpio_top0(.wb_clk_i(clk),.wb_rst_i(rst), .wb_cyc_i(s2_cyc_o),.wb_adr_i(s2_addr_o[7:0]),.wb_dat_i(s2_data_o),.wb_sel_i(s2_sel_o),.wb_we_i(s2_we_o),.wb_stb_i(s2_stb_o),.wb_dat_o(s2_data_i),.wb_ack_o(s2_ack_i),.wb_err_o(),.wb_inta_o(gpio_int),.ext_pad_i(gpio_i_temp),.ext_pad_o(gpio_o),.ext_padoe_o());// fiash控制器连到wb总线互联矩阵的从设备接口3flash_top flash_top0(.wb_clk_i(clk),.wb_rst_i(rst),.wb_adr_i(s3_addr_o),.wb_dat_o(s3_data_i),.wb_dat_i(s3_data_o),.wb_sel_i(s3_sel_o),.wb_we_i(s3_we_o),.wb_stb_i(s3_stb_o), .wb_cyc_i(s3_cyc_o), .wb_ack_o(s3_ack_i),//与小型sopc外部接口相连,对外是flash芯片.flash_adr_o(flash_addr_o),.flash_dat_i(flash_data_i),.flash_rst(flash_rst_o),.flash_oe(flash_oe_o),.flash_ce(flash_ce_o),.flash_we(flash_we_o));// uart控制器连到wb总线互联矩阵的从设备接口1uart_top   uart_top0(.wb_clk_i(clk), .wb_rst_i(rst),.wb_adr_i(s1_addr_o[4:0]),.wb_dat_i(s1_data_o),.wb_dat_o(s1_data_i), .wb_we_i(s1_we_o), .wb_stb_i(s1_stb_o), .wb_cyc_i(s1_cyc_o),.wb_ack_o(s1_ack_i),.wb_sel_i(s1_sel_o),.int_o(uart_int),//连接uart接口.stx_pad_o(uart_out),.srx_pad_i(uart_in),.cts_pad_i(1'b0), .dsr_pad_i(1'b0), .ri_pad_i(1'b0), .dcd_pad_i(1'b0),.rts_pad_o(),  .dtr_pad_o());// sdram控制器连到wb总线互联矩阵的从设备接口0sdrc_top sdrc_top0(.cfg_sdr_width(2'b01),.cfg_colbits(2'b00),.wb_rst_i(rst),.wb_clk_i(clk),.wb_stb_i(s0_stb_o),.wb_ack_o(s0_ack_i),.wb_addr_i({s0_addr_o[25:2],2'b00}),.wb_we_i(s0_we_o),.wb_dat_i(s0_data_o),.wb_sel_i(s0_sel_o),.wb_dat_o(s0_data_i),.wb_cyc_i(s0_cyc_o),.wb_cti_i(3'b000),//连接sdram.sdram_clk(clk),.sdram_resetn(~rst),.sdr_cs_n(sdr_cs_n_o),.sdr_cke(sdr_cke_o),.sdr_ras_n(sdr_ras_n_o),.sdr_cas_n(sdr_cas_n_o),.sdr_we_n(sdr_we_n_o),.sdr_dqm(sdr_dqm_o),.sdr_ba(sdr_ba_o),.sdr_addr(sdr_addr_o),.sdr_dq(sdr_dq_io),//Parameters.sdr_init_done(sdram_init_done),.cfg_req_depth(2'b11),.cfg_sdr_en(1'b1),.cfg_sdr_mode_reg(13'b0000000110001),.cfg_sdr_tras_d(4'b1000),.cfg_sdr_trp_d(4'b0010),.cfg_sdr_trcd_d(4'b0010),.cfg_sdr_cas(3'b100),.cfg_sdr_trcar_d(4'b1010),.cfg_sdr_twr_d(4'b0010),.cfg_sdr_rfsh(12'b011010011000),.cfg_sdr_rfmax(3'b100));wb_conmax_top wb_conmax_top0(.clk_i(clk),.rst_i(rst),// Master 0 Interface,数据接口.m0_data_i(m0_data_i),.m0_data_o(m0_data_o),.m0_addr_i(m0_addr_i),.m0_sel_i(m0_sel_i),.m0_we_i(m0_we_i), .m0_cyc_i(m0_cyc_i), .m0_stb_i(m0_stb_i),.m0_ack_o(m0_ack_o), // Master 1 Interface,指令接口.m1_data_i(m1_data_i),.m1_data_o(m1_data_o),.m1_addr_i(m1_addr_i),.m1_sel_i(m1_sel_i),.m1_we_i(m1_we_i), .m1_cyc_i(m1_cyc_i), .m1_stb_i(m1_stb_i),.m1_ack_o(m1_ack_o), // Slave 0 Interface,sdram控制器.s0_data_i(s0_data_i),.s0_data_o(s0_data_o),.s0_addr_o(s0_addr_o),.s0_sel_o(s0_sel_o),.s0_we_o(s0_we_o), .s0_cyc_o(s0_cyc_o), .s0_stb_o(s0_stb_o),.s0_ack_i(s0_ack_i), .s0_err_i(1'b0), .s0_rty_i(1'b0),// Slave 1 Interface,uart控制器.s1_data_i(s1_data_i),.s1_data_o(s1_data_o),.s1_addr_o(s1_addr_o),.s1_sel_o(s1_sel_o),.s1_we_o(s1_we_o), .s1_cyc_o(s1_cyc_o), .s1_stb_o(s1_stb_o),.s1_ack_i(s1_ack_i), .s1_err_i(1'b0), .s1_rty_i(1'b0),// Slave 2 Interface,gpio接口.s2_data_i(s2_data_i),.s2_data_o(s2_data_o),.s2_addr_o(s2_addr_o),.s2_sel_o(s2_sel_o),.s2_we_o(s2_we_o), .s2_cyc_o(s2_cyc_o), .s2_stb_o(s2_stb_o),.s2_ack_i(s2_ack_i), .s2_err_i(1'b0), .s2_rty_i(1'b0),// Slave 3 Interface,flash控制器.s3_data_i(s3_data_i),.s3_data_o(s3_data_o),.s3_addr_o(s3_addr_o),.s3_sel_o(s3_sel_o),.s3_we_o(s3_we_o), .s3_cyc_o(s3_cyc_o), .s3_stb_o(s3_stb_o),.s3_ack_i(s3_ack_i), .s3_err_i(1'b0), .s3_rty_i(1'b0),);endmodule

从上面可以看到是怎么集成进去的。全书写了几个外设模块的原理,但是一个关键的wb_conmax的实现原理,其实现了总线的上述诸多功能,包括仲裁等。这里只是直接拿来用了,理清这些关系很重要。

为什么flash的地址是0x30000000开始,因为我们是把他接在从设备3了。wb_conmax有规定,根据从设备来设定地址区段。

这些外置的接口ip都是通过mcu操纵其ip内部的寄存器来实现的。比如gpio:

所以要知道外部io口上的数据,只需内核去读这个地址的RGPIO_IN的这个寄存器就可以了。

所以我们实际上理解的编译器,实际上只是将我们的c语言代码编译成最核心的流水线内核的操作指令,涉及到外设的部分仅仅是生成一些操作寄存器的指令,即编译器只是理解外设与寄存器一致,只需生成访存和写回的指令即可。

6、测试与验证

在上面实现后怎么验证,作者用de2的开发板:

由于与mips指令兼容,所以可以使用mips的编译器,生成了inst_rom.o的可重定位elf文件,通过ld文件生成可执行文件,但是有elf文件头,与我们期望的格式还是有很大差别,可以利用mips-sde-elf-objcopy得到.bin的纯二进制格式,这正是我们需要的。(如果是用modelsim仿真,还需将其生成modelsim中存储器初始化文件的格式生成.data文件)

de2中将利用控制面板程序擦写进flash。

注意在编译前要修改ram.ld文件,将其中的起始地址从0x00000000修改为0x30000000,因为前2个测试陈旭是在flash中运行的,而flash的起始地址是0x30000000.

例子3模拟了os的启动过程:

后面是应用程序:

怎么写入flash呢?

《自己动手写cpu》读书笔记相关推荐

  1. 读书笔记 | 墨菲定律

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  2. 读书笔记 | 墨菲定律(一)

    1. 有些事,你现在不做,永远也不会去做. 2. 能轻易实现的梦想都不叫梦想. 3.所有的事都会比你预计的时间长.(做事要有耐心,要经得起前期的枯燥.) 4. 当我们的才华还撑不起梦想时,更要耐下心来 ...

  3. 洛克菲勒的38封信pdf下载_《洛克菲勒写给孩子的38封信》读书笔记

    <洛克菲勒写给孩子的38封信>读书笔记 洛克菲勒写给孩子的38封信 第1封信:起点不决定终点 人人生而平等,但这种平等是权利与法律意义上的平等,与经济和文化优势无关 第2封信:运气靠策划 ...

  4. 股神大家了解多少?深度剖析股神巴菲特

    股神巴菲特是金融界里的传奇,大家是否都对股神巴菲特感兴趣呢?大家对股神了解多少?小编最近在QR社区发现了<阿尔法狗与巴菲特>,里面记载了许多股神巴菲特的人生经历,今天小编简单说一说关于股神 ...

  5. 2014巴菲特股东大会及巴菲特创业分享

     沃伦·巴菲特,这位传奇人物.在美国,巴菲特被称为"先知".在中国,他更多的被喻为"股神",巴菲特在11岁时第一次购买股票以来,白手起家缔造了一个千亿规模的 ...

  6. 《成为沃伦·巴菲特》笔记与感想

    本文首发于微信公众帐号: 一界码农(The_hard_the_luckier) 无需授权即可转载: 甚至无需保留以上版权声明-- 沃伦·巴菲特传记的纪录片 http://www.bilibili.co ...

  7. 读书笔记002:托尼.巴赞之快速阅读

    读书笔记002:托尼.巴赞之快速阅读 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<快速阅读>之后,我们就可以可以快速提高阅读速度,保持并改善理解嗯嗯管理,通过增进了解眼睛和大脑功能 ...

  8. 读书笔记001:托尼.巴赞之开动大脑

    读书笔记001:托尼.巴赞之开动大脑 托尼.巴赞是放射性思维与思维导图的提倡者.读完他的<开动大脑>之后,我们就可以对我们的大脑有更多的了解:大脑可以进行比我们预期多得多的工作:我们可以最 ...

  9. 读书笔记003:托尼.巴赞之思维导图

    读书笔记003:托尼.巴赞之思维导图 托尼.巴赞的<思维导图>一书,详细的介绍了思维发展的新概念--放射性思维:如何利用思维导图实施你的放射性思维,实现你的创造性思维,从而给出一种深刻的智 ...

  10. 产品读书《滚雪球:巴菲特和他的财富人生》

    作者简介 艾丽斯.施罗德,曾经担任世界知名投行摩根士丹利的董事总经理,因为撰写研究报告与巴菲特相识.业务上的往来使得施罗德有更多的机会与巴菲特亲密接触,她不仅是巴菲特别的忘年交,她也是第一个向巴菲特建 ...

最新文章

  1. Linux RSS/RPS/RFS/XPS对比
  2. 【Matlab】parfor并行运算如何显示进度条?
  3. hive中任意相邻时间段数据获取
  4. vue打包成app后,背景图片不显示
  5. 中国移动游戏趋势洞察报告
  6. 自定义手势--输入法手势技术
  7. 东风本田4S店违规收取续保押金 ,电台主持在线怒怼经理,反被指无教养?
  8. 在Keil中利用AStyle插件格式化代码
  9. Spring Boot 2.3.3 正式发布!2.4.0 正式版即将发布!
  10. 深度学习 占用gpu内存 使用率为0_2020年深度学习最佳GPU一览,看看哪一款最适合你!...
  11. 叫号系统是否需要服务器,银行排队叫号方法及系统、服务器及存储介质
  12. iwebAx产品家族之iweb SNS v0.6体验版--不错的开源软件~~
  13. 登录客户端显示不能连接服务器,客户端不能连接服务器,无法登陆
  14. 产业园区数字孪生规划方案
  15. 什么是CDN,CDN有什么作用?
  16. linux 繁体中文转为简体,linux - 安装OpenCC(简体繁体转换)
  17. C语言:判断一个数是否为素数/质数
  18. 快递查询单号查询,分享简单好用查询技巧
  19. 2022年国庆红旗头像制作微信小程序源码
  20. 网易NEC命名规范笔记

热门文章

  1. 2022-2027年中国智能服务机器人行业发展监测及投资战略研究报告
  2. C 通过四个点计算两条直线的交点
  3. 创业感悟:对未来越有信心,对现在就越有耐心
  4. 计算机怎么放映文档,如何从Apple TV上的计算机播放视频文件
  5. 共模信号和差模信号的区别和抑制
  6. linux基本命令总结
  7. PDFjs的使用说明书
  8. 一行代码一道题:求2的幂次方
  9. python中的wx模块
  10. 支付宝客户端拉起支付