ARM Cortex-M0 全可编程SoC原理及实现笔记(1)

对应全书的第九章

目录

  • 一、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所示。
ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第1张图片

图1.1

1.1硬件部分

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

图1.2

1.2软件部分

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

1.3AHB_Lite总线

1.3.1AHB_Lite总线操作

总线操作过程如图1.3所示
ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第3张图片

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

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

1.3.2AHB-Lite主设备接口

  AHB-Lite主设备接口如图1.4和表1.1所示
ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第4张图片

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

ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第5张图片
  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 交易对齐方式

ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第6张图片

1.4Cortex-M0处理器端口描述

ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第7张图片
ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第8张图片

1.5处理器存储器映射属性

ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第9张图片
ARM Cortex-M0 全可编程SoC原理及实现笔记(1)_第10张图片

二、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


你可能感兴趣的:(与ARM有关的一切,fpga开发,嵌入式硬件)