ARM Cortex-M0全可编程SoC原理与实现笔记(第一篇)

对应全书的第九章

目录

  • 一、Cortex-M0架构的全貌是什么
  • 1.1硬件部分
  • 1.2软件部分
  • 1.3AHB_Lite总线
  • 1.3.1AHB_Lite总线操作
  • 1.3.2AHB-Lite主设备接口
  • 1.4Cortex-M0处理器端口描述
  • 1.5处理器存储器映射属性
  • 二、Cortex-M0架构在数字逻辑上怎么实现
  • 2.1顶层文件AHBLITE_SYS
  • 2.2系统主时钟IP核
  • 2.3AHB总线地址译码器AHBDCD
  • 2.4 AHB总线从设备多路复用器
  • 2.5 AHB片上存储器外设
  • 2.6 AHB LED外设
  • 一、Cortex-M0架构的全貌是什么

      Cortex-M0架构分为硬件和软件部分,整个片上系统的内部结构如图1.1所示。

    图1.1

    1.1硬件部分

    硬件部分在FPGA上由纯数字逻辑实现,主要模块包括:
      (1)系统时钟生成器(pll核)
      (2)ARM Cortex-M0微处理器
      (3)AHB-Lite系统总线:
       控制信号,用于同步和识别交易,如:准备,写、读以及传输模式信号
       32位地址总线,用于选择一个外设,或者一个外设中的一个寄存器
       32位数据总线,用于交换数据信息
      (4)两个AHB外设:
       程序存储器,通过FPGA内的块存储器实现
       LED外设
    整个硬件部分的设计如图1.2

    图1.2

    1.2软件部分

    Hello world程序:
      (1)在Keil μVision5中,使用汇编语言对Cortex-M0处理器编程
      (2)建立(build)汇编语言设计文件,生成十六进制的编程文件

    1.3AHB_Lite总线

    1.3.1AHB_Lite总线操作

    总线操作过程如图1.3所示

    图1.3
    处理器访问一个AHB-Lite外设的过程

      (1)处理器提供要访问外设的地址信息
      (2)通过地址译码器生成目标外设的选择信号,同时处理器输出一个控制信号,如读写、传输数据的数量等
      (3)若处理器输出的是读控制信号,则待从设备ready之后读数据

    1.3.2AHB-Lite主设备接口

      AHB-Lite主设备接口如图1.4和表1.1所示

    图1.4AHB-Lite主设备接口

    表1.1AHB-Lite主设备接口信号


      AHB-Lite有四种基本传输类型,如表1.2,交易的同步和识别由处理器的控制信号给出.

    表1.2 AHB-Lite交易类型

    交易 访问 描述
    HSTRANS[1:0]=2’b00 空闲 处理器不希望处理任何交易
    HSTRANS[1:0]=2’b10
    HPROT[0]=1’b0
    HSIZE[1:0]=2’b10
    HWRITE=1’b0
    取指 处理器取指操作,处理器一次性从存储器取出32位指令
    HSTRANS[1:0]=2’b10
    HPROT[0]=1’b1
    HSIZE[1:0]=2’b00
    字节 处理器希望一个8位数据访问操作,该操作由LDRB,LDRBS,STRB指令生成。加载执行将驱动HWRITE信号为低,保存指令将驱动HWRITE指令为高
    HSTRANS[1:0]=2’b10
    HPROT[0]=1’b1
    HSIZE[1:0]=2’b01
    半字 处理器希望一个16位数据访问操作,该操作由LDRH,LDRHS,STRH指令生成。加载执行将驱动HWRITE信号为低,保存指令将驱动HWRITE指令为高
    HSTRANS[1:0]=2’b10
    HPROT[0]=1’b1
    HSIZE[1:0]=2’b10
    处理器希望执行一个由LDR,LDM,POP,STR,STM,PUSH指令,或者异常入口的一部分,或者返回所产生的32位数据访问操作,加载执行将驱动HWRITE信号为低,保存指令将驱动HWRITE指令为高

    其中各指令和异常、返回的概念在软件部分介绍

      Cortex-M0处理器总是工作在小端模式,所有交易总是自然对齐,怎么对齐如表1.3所示

    表1.3 交易对齐方式

    1.4Cortex-M0处理器端口描述


    1.5处理器存储器映射属性


    二、Cortex-M0架构在数字逻辑上怎么实现

    看代码,怎么才算看懂代码或者数学公式?能用中文说出来就算看懂

    2.1顶层文件AHBLITE_SYS

      代码如下

    
    module AHBLITE_SYS(
    	//CLOCKS & RESET
    	input		wire				CLK,
    	input		wire				RESET, 
    	
    	//TO BOARD LEDs
    	output 	wire	[7:0] 	LED
    
    );
     
    //AHB-LITE SIGNALS 
    //Gloal Signals
    wire 				HCLK;
    wire 				HRESETn;
    //Address, Control & Write Data Signals
    wire [31:0]		HADDR;
    wire [31:0]		HWDATA;
    wire 				HWRITE;
    wire [1:0] 		HTRANS;
    wire [2:0] 		HBURST;
    wire 				HMASTLOCK;
    wire [3:0] 		HPROT;
    wire [2:0] 		HSIZE;
    //Transfer Response & Read Data Signals
    wire [31:0] 	HRDATA;
    wire 				HRESP;
    wire 				HREADY;
    
    //SELECT SIGNALS
    wire [3:0] 		MUX_SEL;
    
    wire 				HSEL_MEM;
    wire 				HSEL_LED;
    
    //SLAVE READ DATA
    wire [31:0] 	HRDATA_MEM;
    wire [31:0] 	HRDATA_LED;
    
    //SLAVE HREADYOUT
    wire 				HREADYOUT_MEM;
    wire 				HREADYOUT_LED;
    
    //CM0-DS Sideband signals
    wire 				LOCKUP;
    wire 				TXEV;
    wire 				SLEEPING;
    wire [15:0]		IRQ;
      
    //SYSTEM GENERATES NO ERROR RESPONSE
    assign 			HRESP = 1'b0;
    
    //CM0-DS INTERRUPT SIGNALS  
    assign 			IRQ = {16'b0000_0000_0000_0000};
    
    // Clock divider, divide the frequency by two, hence less time constraint 
     clk_wiz_0 Inst_clk_wiz_0
     (
     // Clock in ports
      .clk_in1(CLK),      // input clk_in1
      // Clock out ports
      .clk_out1(HCLK),     // output clk_out1
      // Status and control signals
      .reset(RESET), // input reset
      .locked(HRESETn));      // output locked
    // INST_TAG_END ------ End INSTANTIATION Template ---------     
    
    //AHBLite MASTER --> CM0-DS
    
    CORTEXM0DS u_cortexm0ds (
    	//Global Signals
    	.HCLK        (HCLK),
    	.HRESETn     (HRESETn),
    	//Address, Control & Write Data	
    	.HADDR       (HADDR[31:0]),
    	.HBURST      (HBURST[2:0]),
    	.HMASTLOCK   (HMASTLOCK),
    	.HPROT       (HPROT[3:0]),
    	.HSIZE       (HSIZE[2:0]),
    	.HTRANS      (HTRANS[1:0]),
    	.HWDATA      (HWDATA[31:0]),
    	.HWRITE      (HWRITE),
    	//Transfer Response & Read Data	
    	.HRDATA      (HRDATA[31:0]),			
    	.HREADY      (HREADY),					
    	.HRESP       (HRESP),					
    
    	//CM0 Sideband Signals
    	.NMI         (1'b0),
    	.IRQ         (IRQ[15:0]),
    	.TXEV        (),
    	.RXEV        (1'b0),
    	.LOCKUP      (LOCKUP),
    	.SYSRESETREQ (),
    	.SLEEPING    ()
    );
    
    //Address Decoder 
    
    AHBDCD uAHBDCD (
    	.HADDR(HADDR[31:0]),
    	 
    	.HSEL_S0(HSEL_MEM),
    	.HSEL_S1(HSEL_LED),
    	.HSEL_S2(),
    	.HSEL_S3(),
    	.HSEL_S4(),
    	.HSEL_S5(),
    	.HSEL_S6(),
    	.HSEL_S7(),
    	.HSEL_S8(),
    	.HSEL_S9(),
    	.HSEL_NOMAP(HSEL_NOMAP),
    	 
    	.MUX_SEL(MUX_SEL[3:0])
    );
    
    //Slave to Master Mulitplexor
    
    AHBMUX uAHBMUX (
    	.HCLK(HCLK),
    	.HRESETn(HRESETn),
    	.MUX_SEL(MUX_SEL[3:0]),
    	 
    	.HRDATA_S0(HRDATA_MEM),
    	.HRDATA_S1(HRDATA_LED),
    	.HRDATA_S2(),
    	.HRDATA_S3(),
    	.HRDATA_S4(),
    	.HRDATA_S5(),
    	.HRDATA_S6(),
    	.HRDATA_S7(),
    	.HRDATA_S8(),
    	.HRDATA_S9(),
    	.HRDATA_NOMAP(32'hDEADBEEF),
    	 
    	.HREADYOUT_S0(HREADYOUT_MEM),
    	.HREADYOUT_S1(HREADYOUT_LED),
    	.HREADYOUT_S2(1'b1),
    	.HREADYOUT_S3(1'b1),
    	.HREADYOUT_S4(1'b1),
    	.HREADYOUT_S5(1'b1),
    	.HREADYOUT_S6(1'b1),
    	.HREADYOUT_S7(1'b1),
    	.HREADYOUT_S8(1'b1),
    	.HREADYOUT_S9(1'b1),
    	.HREADYOUT_NOMAP(1'b1),
        
    	.HRDATA(HRDATA[31:0]),
    	.HREADY(HREADY)
    );
    
    // AHBLite Peripherals
    
    
    //AHBLite Slave 
    AHB2MEM uAHB2MEM (
    	//AHBLITE Signals
    	.HSEL(HSEL_MEM),
    	.HCLK(HCLK), 
    	.HRESETn(HRESETn), 
    	.HREADY(HREADY),     
    	.HADDR(HADDR),
    	.HTRANS(HTRANS[1:0]), 
    	.HWRITE(HWRITE),
    	.HSIZE(HSIZE),
    	.HWDATA(HWDATA[31:0]), 
    	
    	.HRDATA(HRDATA_MEM), 
    	.HREADYOUT(HREADYOUT_MEM)
    	//Sideband Signals
    	
    );
    
    //AHBLite Slave 
    AHB2LED uAHB2LED (
    	//AHBLITE Signals
    	.HSEL(HSEL_LED),
    	.HCLK(HCLK), 
    	.HRESETn(HRESETn), 
    	.HREADY(HREADY),     
    	.HADDR(HADDR),
    	.HTRANS(HTRANS[1:0]), 
    	.HWRITE(HWRITE),
    	.HSIZE(HSIZE),
    	.HWDATA(HWDATA[31:0]), 
    	
    	.HRDATA(HRDATA_LED), 
    	.HREADYOUT(HREADYOUT_LED),
    	//Sideband Signals
    	.LED(LED[7:0])
    );
    
    
    endmodule
    

    2.2系统主时钟IP核

    输出20MHz时钟作为系统主时钟

    2.3AHB总线地址译码器AHBDCD

      注意该模块为纯组合逻辑,没有全局时钟和复位信号

    module AHBDCD(
      input wire [31:0] HADDR,
      
      output wire HSEL_S0,
      output wire HSEL_S1,
      output wire HSEL_S2,
      output wire HSEL_S3,
      output wire HSEL_S4,
      output wire HSEL_S5,
      output wire HSEL_S6,
      output wire HSEL_S7,
      output wire HSEL_S8,
      output wire HSEL_S9,
      output wire HSEL_NOMAP,
      
      output reg [3:0] MUX_SEL
        );
    
    reg [15:0] dec;
    
    //REFER CM0-DS REFERENC MANUAL FOR RAM & PERIPHERAL MEMORY MAP
    //									//MEMORY MAP --> START ADDR 		END ADDR 	SIZE 
    assign HSEL_S0 = dec[0];   //MEMORY MAP --> 0x0000_0000 to 0x00FF_FFFF  16MB
    assign HSEL_S1 = dec[1];   //MEMORY MAP --> 0x5000_0000 to 0x50FF_FFFF  16MB	
    assign HSEL_S2 = dec[2];   //MEMORY MAP --> 0x5100_0000 to 0x51FF_FFFF  16MB
    assign HSEL_S3 = dec[3];   //MEMORY MAP --> 0x5200_0000 to 0x52FF_FFFF  16MB
    assign HSEL_S4 = dec[4];   //MEMORY MAP --> 0x5300_0000 to 0x53FF_FFFF  16MB
    assign HSEL_S5 = dec[5];   //MEMORY MAP --> 0x5400_0000 to 0x54FF_FFFF  16MB
    assign HSEL_S6 = dec[6];   //MEMORY MAP --> 0x5500_0000 to 0x55FF_FFFF  16MB
    assign HSEL_S7 = dec[7];   //MEMORY MAP --> 0x5600_0000 to 0x56FF_FFFF  16MB
    assign HSEL_S8 = dec[8];   //MEMORY MAP --> 0x5700_0000 to 0x57FF_FFFF  16MB
    assign HSEL_S9 = dec[9];   //MEMORY MAP --> 0x5800_0000 to 0x58FF_FFFF  16MB
    assign HSEL_NOMAP = dec[15]; //REST OF REGION NOT COVERED ABOVE
        
    always@*
    begin
    
      case(HADDR[31:24])
        8'h00: 						//MEMORY MAP --> 0x0000_0000 to 0x00FF_FFFF  16MB
          begin
            dec = 16'b0000_0000_00000001;
            MUX_SEL = 4'b0000;
          end
        8'h50: 						//MEMORY MAP --> 0x5000_0000 to 0x50FF_FFFF  16MB 
          begin
            dec = 16'b0000_0000_0000_0010;
            MUX_SEL = 4'b0001;
          end
        8'h51: 						//MEMORY MAP --> 0x5100_0000 to 0x51FF_FFFF  16MB
          begin
            dec =16'b0000_0000_0000_0100;
            MUX_SEL = 4'b0010;
          end   
        8'h52:  					//MEMORY MAP --> 0x5200_0000 to 0x52FF_FFFF  16MB
          begin
            dec = 16'b0000_0000_0000_1000;
            MUX_SEL = 4'b0011;
          end
        8'h53: 						//MEMORY MAP --> 0x5300_0000 to 0x53FF_FFFF  16MB 
          begin
            dec = 16'b0000_0000_0001_0000;
            MUX_SEL = 4'b0100;
          end
        8'h54:						//MEMORY MAP --> 0x5400_0000 to 0x54FF_FFFF  16MB  
          begin
            dec = 16'b0000_0000_0010_0000;
            MUX_SEL = 4'b0101;
          end
        8'h55:						//MEMORY MAP --> 0x5500_0000 to 0x55FF_FFFF  16MB 
          begin
            dec = 16'b0000_0000_0100_0000;
            MUX_SEL = 4'b0110;
          end
        8'h56:						//MEMORY MAP --> 0x5600_0000 to 0x56FF_FFFF  16MB 
          begin
            dec = 16'b0000_0000_1000_0000;
            MUX_SEL = 4'b0111;
          end
        8'h57: 						//MEMORY MAP --> 0x5700_0000 to 0x57FF_FFFF  16MB
          begin
            dec = 16'b0000_0001_0000_0000;
            MUX_SEL = 4'b1000;
          end
        8'h58:						//MEMORY MAP --> 0x5800_0000 to 0x58FF_FFFF  16MB 
          begin
            dec = 16'b0000_0010_0000_0000;
            MUX_SEL = 4'b1001;
          end
        default: //NOMAP
          begin
            dec = 16'b1000_0000_00000000;
            MUX_SEL = 4'b1111;
          end
      endcase
    end
    
    endmodule
    
    

      AHB地址译码器模块根据地址信号的高八位HADDR[31:24]来输出十个外设使能HSEL与NOMAP信号,和使能外设地址号MUX_SEL,其中各信号映射如表2.1。

    HADDR[31:24] dec MUX_SEL MEMORY MAP
    8’h00 HSEL_S0 0 0x0000_0000 to 0x00FF_FFFF 16MB
    8’h50 HSEL_S1 1 0x5000_0000 to 0x00FF_FFFF 16MB
    8’h51 HSEL_S2 2 0x5100_0000 to 0x00FF_FFFF 16MB
    8’h52 HSEL_S3 3 0x5200_0000 to 0x00FF_FFFF 16MB
    8’h53 HSEL_S4 4 0x5300_0000 to 0x00FF_FFFF 16MB
    8’h54 HSEL_S5 5 0x5400_0000 to 0x00FF_FFFF 16MB
    8’h55 HSEL_S6 6 0x5500_0000 to 0x00FF_FFFF 16MB
    8’h56 HSEL_S7 7 0x5600_0000 to 0x00FF_FFFF 16MB
    8’h57 HSEL_S8 8 0x5700_0000 to 0x00FF_FFFF 16MB
    8’h58 HSEL_S9 9 0x5800_0000 to 0x00FF_FFFF 16MB
    default HSEL_NOMAP 15 none

    表2.1
      该表是各外设在ram中的地址映射,每个外设都分配了16MB的地址,注意s0外设的起始位与其他的不一样,外设与ram中的地址映射可参考CM0-DS手册,其中HSEL_S0与HSEL_S1将分别与外部存储器和LED模块相连。   对于32位地址信号HADDR,0x40000000~0x5FFFFFFF的部分是推荐给外设使用的。

    2.4 AHB总线从设备多路复用器

      选择从设备的读数据和ready信号给主设备。在地址阶段锁存MUX_SEL,在数据阶段输出READY(RESPONSE貌似外设都没用到)和RDATA。由代码可知,S0(即片上存储器)必须先READY

    
     
    module AHBMUX(
      //GLOBAL CLOCK & RESET
      input wire HCLK,
      input wire HRESETn,
       
      //MUX SELECT FROM ADDRESS DECODER
      input wire [3:0] MUX_SEL,
    
      //READ DATA FROM ALL THE SLAVES  
      input wire [31:0] HRDATA_S0,		
      input wire [31:0] HRDATA_S1,
      input wire [31:0] HRDATA_S2,
      input wire [31:0] HRDATA_S3,
      input wire [31:0] HRDATA_S4,
      input wire [31:0] HRDATA_S5,
      input wire [31:0] HRDATA_S6,
      input wire [31:0] HRDATA_S7,
      input wire [31:0] HRDATA_S8,
      input wire [31:0] HRDATA_S9,
      input wire [31:0] HRDATA_NOMAP,
    
      //READYOUT FROM ALL THE SLAVES  
      input wire HREADYOUT_S0,
      input wire HREADYOUT_S1,
      input wire HREADYOUT_S2,
      input wire HREADYOUT_S3,
      input wire HREADYOUT_S4,
      input wire HREADYOUT_S5,
      input wire HREADYOUT_S6,
      input wire HREADYOUT_S7,
      input wire HREADYOUT_S8,
      input wire HREADYOUT_S9,
      input wire HREADYOUT_NOMAP,
     
      //MULTIPLEXED HREADY & HRDATA TO MASTER
      output reg HREADY,
      output reg [31:0] HRDATA
    );
    
     
      reg [3:0] APHASE_MUX_SEL;			// LATCH THE ADDRESS PHASE MUX_SELECT
    												// TO SEND THE APPROPRIATE RESPONSE & RDATA
    												// IN THE DATA PHASE
      always@ (posedge HCLK or negedge HRESETn)
      begin
        if(!HRESETn)
          APHASE_MUX_SEL <= 4'h0;
        else if(HREADY)						// NOTE: ALL THE CONTROL SIGNALS ARE VALID ONLY IF HREADY = 1'b1
          APHASE_MUX_SEL <= MUX_SEL;
      end
    
    
      always@*
      begin
        case(APHASE_MUX_SEL)
          4'b0000: begin						// SELECT SLAVE0 RESPONSE & DATA IF PREVIOUS APHASE WAS FOR S0
            HRDATA = HRDATA_S0;
            HREADY = HREADYOUT_S0;
          end
          4'b0001: begin
            HRDATA = HRDATA_S1;
            HREADY = HREADYOUT_S1;
          end
          4'b0010: begin
            HRDATA = HRDATA_S2;
            HREADY = HREADYOUT_S2;
          end
          4'b0011: begin
            HRDATA = HRDATA_S3;
            HREADY = HREADYOUT_S3;
          end
          4'b0100: begin
            HRDATA = HRDATA_S4;
            HREADY = HREADYOUT_S4;
          end
          4'b0101: begin
            HRDATA = HRDATA_S5;
            HREADY = HREADYOUT_S5;
          end
          4'b0110: begin
            HRDATA = HRDATA_S6;
            HREADY = HREADYOUT_S6;
          end
          4'b0111: begin
            HRDATA = HRDATA_S7;
            HREADY = HREADYOUT_S7;
          end
          4'b1000: begin
            HRDATA = HRDATA_S8;
            HREADY = HREADYOUT_S8;
          end
          4'b1001: begin
            HRDATA = HRDATA_S9;
            HREADY = HREADYOUT_S9;
          end
          default: begin            
            HRDATA = HRDATA_NOMAP;
            HREADY = HREADYOUT_NOMAP;
          end
        endcase
        
      end
    
    
    endmodule
    
    

    2.5 AHB片上存储器外设

      软件程序最终会被翻译为机器指令,片上存储器就是存储机器指令的地方,由FPGA上的BRAM(块存储器)实现

    //  --
    module AHB2MEM
    #(parameter MEMWIDTH = 10)					// SIZE = 1KB = 256 Words
    (
    	//AHBLITE INTERFACE
    		//Slave Select Signals
    			input wire HSEL,
    		//Global Signal
    			input wire HCLK,
    			input wire HRESETn,
    		//Address, Control & Write Data
    			input wire HREADY,
    			input wire [31:0] HADDR,
    			input wire [1:0] HTRANS,
    			input wire HWRITE,
    			input wire [2:0] HSIZE,
    			
    			input wire [31:0] HWDATA,
    		// Transfer Response & Read Data
    			output wire HREADYOUT,
    			output wire [31:0] HRDATA,
    	
    	//LED Output
    			output wire [7:0] LED
    );
    
    
      assign HREADYOUT = 1'b1; // Always ready
    
    // Registers to store Adress Phase Signals
     
      reg APhase_HSEL;
      reg APhase_HWRITE;
      reg [1:0] APhase_HTRANS;
      reg [31:0] APhase_HADDR;
      reg [2:0] APhase_HSIZE;
    
    // Memory Array  
      reg [31:0] memory[0:(2**(MEMWIDTH-2)-1)];
      
      initial
      begin
    (*rom_style="block"*)	 $readmemh("code.hex", memory);
      end
    
    // Sample the Address Phase   
      always @(posedge HCLK or negedge HRESETn)
      begin
    	 if(!HRESETn)
    	 begin
    		APhase_HSEL <= 1'b0;
          APhase_HWRITE <= 1'b0;
          APhase_HTRANS <= 2'b00;
    		APhase_HADDR <= 32'h0;
    		APhase_HSIZE <= 3'b000;
    	 end
        else if(HREADY)
        begin
          APhase_HSEL <= HSEL;
          APhase_HWRITE <= HWRITE;
          APhase_HTRANS <= HTRANS;
    		APhase_HADDR <= HADDR;
    		APhase_HSIZE <= HSIZE;
        end
      end
    
    // Decode the bytes lanes depending on HSIZE & HADDR[1:0]
    
      wire tx_byte = ~APhase_HSIZE[1] & ~APhase_HSIZE[0];
      wire tx_half = ~APhase_HSIZE[1] &  APhase_HSIZE[0];
      wire tx_word =  APhase_HSIZE[1];
      
      wire byte_at_00 = tx_byte & ~APhase_HADDR[1] & ~APhase_HADDR[0];
      wire byte_at_01 = tx_byte & ~APhase_HADDR[1] &  APhase_HADDR[0];
      wire byte_at_10 = tx_byte &  APhase_HADDR[1] & ~APhase_HADDR[0];
      wire byte_at_11 = tx_byte &  APhase_HADDR[1] &  APhase_HADDR[0];
      
      wire half_at_00 = tx_half & ~APhase_HADDR[1];
      wire half_at_10 = tx_half &  APhase_HADDR[1];
      
      wire word_at_00 = tx_word;
      
      wire byte0 = word_at_00 | half_at_00 | byte_at_00;
      wire byte1 = word_at_00 | half_at_00 | byte_at_01;
      wire byte2 = word_at_00 | half_at_10 | byte_at_10;
      wire byte3 = word_at_00 | half_at_10 | byte_at_11;
    
    // Writing to the memory
    
    // Student Assignment: Write a testbench & simulate to spot bugs in this Memory module
    
      always @(posedge HCLK)
      begin
    	 if(APhase_HSEL & APhase_HWRITE & APhase_HTRANS[1])
    	 begin
    		if(byte0)
    			memory[APhase_HADDR[MEMWIDTH:2]][7:0] <= HWDATA[7:0];
    		if(byte1)
    			memory[APhase_HADDR[MEMWIDTH:2]][15:8] <= HWDATA[15:8];
    		if(byte2)
    			memory[APhase_HADDR[MEMWIDTH:2]][23:16] <= HWDATA[23:16];
    		if(byte3)
    			memory[APhase_HADDR[MEMWIDTH:2]][31:24] <= HWDATA[31:24];
    	  end
      end
    
    // Reading from memory 
      assign HRDATA = memory[APhase_HADDR[MEMWIDTH:2]];
    
    // Diagnostic Signal out
    assign zeroth_location = 0;
    assign LED = memory[zeroth_location][7:0];
      
    endmodule
    
    

      分析下面这一段代码,若将表1.3中的7种情况编号,则byte0表示第1、5、7种情况,byte1表示第2、5、7种情况,byte2表示第3、6、7种情况,byte1表示第4、6、7种情况。
      APhase_HADDR[MEMWIDTH:2]表示把输入的地址除以4,为什么要这样做?因为一个字有四个字节。S0端口号对应的地址范围为0x00000000~0x00FFFFFF,而片上存储器只有1kb,所以其地址范围为0x00000000~0x000003FF,即MEMWIDTH那么多位的空间,但要右移2位,再写入对应的字节通道,因为一个字有四个字节。所以知道为什么C++要字节对齐了吧。

      wire byte0 = word_at_00 | half_at_00 | byte_at_00;
      wire byte1 = word_at_00 | half_at_00 | byte_at_01;
      wire byte2 = word_at_00 | half_at_10 | byte_at_10;
      wire byte3 = word_at_00 | half_at_10 | byte_at_11;
    
    // Writing to the memory
    
    // Student Assignment: Write a testbench & simulate to spot bugs in this Memory module
    
      always @(posedge HCLK)
      begin
    	 if(APhase_HSEL & APhase_HWRITE & APhase_HTRANS[1])
    	 begin
    		if(byte0)
    			memory[APhase_HADDR[MEMWIDTH:2]][7:0] <= HWDATA[7:0];
    		if(byte1)
    			memory[APhase_HADDR[MEMWIDTH:2]][15:8] <= HWDATA[15:8];
    		if(byte2)
    			memory[APhase_HADDR[MEMWIDTH:2]][23:16] <= HWDATA[23:16];
    		if(byte3)
    			memory[APhase_HADDR[MEMWIDTH:2]][31:24] <= HWDATA[31:24];
    	  end
      end
    

      其中这一段,是将程序文件预加载到硬件中,因为要将生成的软件程序镜像文件与硬件文件合并。但是为什么这里memory加载了软件程序后还能赋值HWDATA呢? 后续揭晓

     initial
      begin
    (*rom_style="block"*)	 $readmemh("code.hex", memory);
      end
    

    2.6 AHB LED外设

      将写数据的低八位显示在8个LED灯上

    module AHB2LED(
    	//AHBLITE INTERFACE
    		//Slave Select Signals
    			input wire HSEL,
    		//Global Signal
    			input wire HCLK,
    			input wire HRESETn,
    		//Address, Control & Write Data
    			input wire HREADY,
    			input wire [31:0] HADDR,
    			input wire [1:0] HTRANS,
    			input wire HWRITE,
    			input wire [2:0] HSIZE,
    			
    			input wire [31:0] HWDATA,
    		// Transfer Response & Read Data
    			output wire HREADYOUT,
    			output wire [31:0] HRDATA,
    		//LED Output
    			output wire [7:0] LED
    );
    
    //Address Phase Sampling Registers
      reg rHSEL;
      reg [31:0] rHADDR;
      reg [1:0] rHTRANS;
      reg rHWRITE;
      reg [2:0] rHSIZE;
    
      reg [7:0] rLED;
     
    //Address Phase Sampling
      always @(posedge HCLK or negedge HRESETn)
      begin
    	 if(!HRESETn)
    	 begin
    		rHSEL		<= 1'b0;
    		rHADDR	<= 32'h0;
    		rHTRANS	<= 2'b00;
    		rHWRITE	<= 1'b0;
    		rHSIZE	<= 3'b000;
    	 end
        else if(HREADY)
        begin
          rHSEL		<= HSEL;
    		rHADDR	<= HADDR;
    		rHTRANS	<= HTRANS;
    		rHWRITE	<= HWRITE;
    		rHSIZE	<= HSIZE;
        end
      end
    
    //Data Phase data transfer
      always @(posedge HCLK or negedge HRESETn)
      begin
        if(!HRESETn)
          rLED <= 8'b0000_0000;
        else if(rHSEL & rHWRITE & rHTRANS[1])
          rLED <= HWDATA[7:0];
      end
    
    //Transfer Response
      assign HREADYOUT = 1'b1; //Single cycle Write & Read. Zero Wait state operations
    
    //Read Data  
      assign HRDATA = {24'h0000_00,rLED};
    
      assign LED = rLED;
    
    endmodule
    
    
    

    作者:一叽咕咕咕

    物联沃分享整理
    物联沃-IOTWORD物联网 » ARM Cortex-M0全可编程SoC原理与实现笔记(第一篇)

    发表评论