2008年11月26日

BF532芯片内调试UART程序

今天写了一段UART串口消息输出调试代码,用于加载到芯片L1 RAM中运行测试UART的连接情况,成功输出信息:Hello Bfincn
代码比较简单,大家看看就明白了。

#include "bin2ldr.h"

#define hi(x) (x >> 16)
#define lo(x) (x & 0xffff)

/* UART Controller (0xFFC00400 - 0xFFC004FF) */
/* Transmit Holding register */
#define UART_THR 0xFFC00400
/* Receive Buffer register */
#define UART_RBR 0xFFC00400
/* Divisor Latch (Low-Byte) */
#define UART_DLL 0xFFC00400
/* Interrupt Enable Register */
#define UART_IER 0xFFC00404
/* Divisor Latch (High-Byte) */
#define UART_DLH 0xFFC00404
/* Interrupt Identification Register */
#define UART_IIR 0xFFC00408
/* Line Control Register */
#define UART_LCR 0xFFC0040C
/* Modem Control Register */
#define UART_MCR 0xFFC00410
/* Line Status Register */
#define UART_LSR 0xFFC00414
/* SCR Scratch Register */
#define UART_SCR 0xFFC0041C
/* Global Control Register */
#define UART_GCTL 0xFFC00424


/* Initialise UART */
p0.h = hi(UART_LCR);
p0.l = lo(UART_LCR);

/* 8-bit word; 1 stop bit; No parity */
r0 = 0x83(Z);
w[p0] = r0.l; /* To enable DLL writes */
ssync;

p0.h = hi(UART_DLL);
p0.l = lo(UART_DLL);

/* SCLK = 133MHz, BaudRate=115200
BaudRate = SCLK /(16 * Divisor) */
r0 = 0x48(Z);
w[p0] = r0.l;
ssync;

p0.h = hi(UART_DLH);
p0.l = lo(UART_DLH);
r0 = 0x00(Z);
w[p0] = r0.l;
ssync;

p0.h = hi(UART_GCTL);
p0.l = lo(UART_GCTL);
r0 = 0x1(Z);
w[p0] = r0.l; /* To enable UART clock */
ssync;

/* Begin to process rx/tx data */
p0.h = hi(UART_LCR);
p0.l = lo(UART_LCR);

/* 8-bit word; 1 stop bit; No parity */
r0 = 0x03(Z);
/* To enable access THR/PBR */
w[p0] = r0.l;
ssync;

/* Write 'Hello Bfincn' to Console */
p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x48(Z); /* H */
w[p0] = r0.l;
ssync;

ww1:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww1;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x65(Z); /* e */
w[p0] = r0.l;
ssync;

ww2:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww2;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x6c(Z); /* l */
w[p0] = r0.l;
ssync;

ww3:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww3;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x6c(Z); /* l */
w[p0] = r0.l;
ssync;

ww4:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww4;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x6f(Z); /* l */
w[p0] = r0.l;
ssync;

ww5:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww5;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x20(Z); /* space */
w[p0] = r0.l;
ssync;

ww6:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww6;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x42(Z); /* B */
w[p0] = r0.l;
ssync;

ww7:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww7;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x66(Z); /* f */
w[p0] = r0.l;
ssync;

ww8:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww8;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x69(Z); /* i */
w[p0] = r0.l;
ssync;

ww9:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww9;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x6e(Z); /* n */
w[p0] = r0.l;
ssync;

ww10:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww10;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x63(Z); /* c */
w[p0] = r0.l;
ssync;

ww11:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump ww11;

p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
r0 = 0x6e(Z); /* n */
w[p0] = r0.l;
ssync;

ww12:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,0);
if !cc jump ww12;

/* read from buffer */
p0.h = hi(UART_RBR);
p0.l = lo(UART_RBR);
r1 = w[p0](z);

/* send buffer is empty or not */
wait:
p0.h = hi(UART_LSR);
p0.l = lo(UART_LSR);
r0 = w[p0](z);
cc = bittst(r0,5);
if !cc jump wait;

/* write back to console */
p0.h = hi(UART_THR);
p0.l = lo(UART_THR);
w[p0] = r1.l;
ssync;

/* if user enter the char 'q' then exit */
r1 = 0x72(z);
cc = r0 == r1; /* q */
if !cc jump ww12;

p0.l = (APP_ENTRY & 0xFFFF);
p0.h = (APP_ENTRY >> 16);
jump (p0);

2008年11月25日

看图学布线










2008年11月23日

掌握高级处理器特性可提高编码效率

掌握高级处理器特性可提高编码效率
数字信号处理器(DSP)在性能、外设、功耗和价格上已经结合得非常好了,许多系统工程师希望利用DSP的优势,取代传统设计方案中使用的处理器,但一个 潜在难题是设计工程师已经为他们的应用开发了大量C和C++代码。很明显,工程师都愿意在DSP平台上利用现有的高级代码,同时利用DSP的体系结构特性 以获得更好的性能。

  HLL与汇编语言

  当开发基于DSP的软件时,必须要做的一项工作就是确定使用哪一种程序设计方法学,通常是在汇编语言和高级语言(HLL)(例如C或C++语言)之间进行选择。

  C和C++的优点包括模块性、便携性以及可重复利用性。

  传统的汇编语言由于其语法和缩写难以理解和使用,长期以来不被人们所看好。目前的“代数语法”体系结构有了很大改进。表1是使用传统风格和使用代数格式的典型DSP指令实例,很显然后者的结构更加直观。在所提供的实例中,r寄存器是数据寄存器,p寄存器是指针寄存器。

  用汇编语言编程困难的一个原因是由于其数据流集中在DSP实际寄存器组、计算单元和存储器之间。用C或C++语言编程,这种操作通常通过使用变量和函数,或过程调用出现在更加抽象的处理


等级之间,从而使得代码更容易跟随。

  为提高DSP执行效率,工具开发商会使用汇编语言对重要的数据密集代码模块进行优化。HLL编译优化转换可以很好地完成该项工作,而且对DSP 数据流和计算的直接控制能力是极为出色的。这就是为什么设计工程师通常结合使用C/C++和汇编语言。HLL适合于控制和基本的数据操作,而汇编语言适合 于高效的数字计算。

  适合高效编程的体系结构的特性

  为了使汇编语言程序员能够有效地完成工作,需要了解处理器的结构类型,以便能够区分不适合高速数字计算的那些DSP处理器。这些适合高效编程的体系结构结构特性包括:

  ● 专用寻址模式

  ● 硬件环路结构

  ● 高速缓冲存储器

  ● 每周期多次操作

  ● 互锁流水线

  ● 灵活的数据寄存器文挡

  专用寻址模式

  允许处理器在单周期内访问多个数据字需要灵活的地址产生方式。除了需要更大的以DSP为中心的16bit和32bit边界的访问尺寸外,还需要 字节寻址以达到最有效的处理。这是非常重要的,因为一些普通应用(例如许多基于视频的系统)都是按照8bit数据操作。当处理器访问限制在单一边界内时, 处理器可能需要额外的周期来掩蔽掉相关的位。

  另外一种有利的寻址能力是“循环缓冲”。该特性必须直接由处理器支持,无须专门的软件管理开销。循环缓冲允许程序员定义存储器中的缓冲器,并且 自动跨越它们。一旦缓冲器设置好,则无须专门的软件交互操作数据。地址发生器处理非同式跨幅,更重要的是可以处理图1所示的“环绕式”特性。如果没有这种 自动地址产生功能,程序员必须手动跟踪缓冲器,从而浪费了宝贵的处理周期。

图1 环绕式缓冲的例子

  在此例中,基地址和起始索引地址=0x0;索引地址寄存器I0指向地址0x0;缓冲器长度L=44(11个数据元素×4字节/元素);修改寄存器M0=16(4个数据元素×4字节/元素)

  实例代码:

  R0 = [I0++M0]; //R0 = 1,I0在代码执行后指向0x10

  R1 = [I0++M0]; //R1 = 5,I0在代码执行后指向0x20

  R2 = [I0++M0]; //R2 = 9,I0在代码执行后指向0x04

  R3 = [I0++M0]; //R3 = 2,I0在代码执行后指向0x14

  R4 = [I0++M0]; //R4 = 6,I0在代码执行后指向0x24

  用于高效信号处理运算(例如快速傅立叶变换(FFT)和离散余弦变换(DCT))的一种重要寻址模式是比特翻转。顾名思义,“比特翻转”就是将 二进制地址中的比特翻转,也就是说将权值最小的比特与权值最大的比特交换位置。由基为2的蝶形所要求的数据顺序是“已翻转比特”的顺序,因此比特翻转索引 用来组合FFT级。可以计算软件中的这些比特翻转索引,但是这样做的效率非常低。图2所示是比特翻转地址流实例。

图2 硬件比特翻转机理

  实例代码:

  LSETUP(起始, 终止)LC0=P0; //循环数P0=8

  起始:R0 = [I0] || I0 += M0(BREV); //I0指向输入缓冲器,在比特翻转过程中自动增加

  终止:[I2++] = R0; ; //I2指向比特翻转缓冲器

硬件循环结构

  循环在通信处理算法中是一项很重要的特性。有两个与循环有关的关键特性能够改进多种算法的性能。第一个特性称作“零开销硬件循环”。随着寻址能 力的提高,循环结构可以在硬件中实现。此外,当该项功能用软件实现时,相关的开销可减小到实时处理预算。零开销循环允许程序员通过设置计数值并且定义循环 边界初始化循环。处理器将继续执行循环直到计数结束。

  零开销循环是大多数处理器必不可少的一部分,但“硬件循环缓冲器”实际上可以提高循环结构的性能。它们用作循环中所执行指令的一种高速缓冲存储 器。例如,在第一次执行完一个循环之后,可将该指令保存在循环缓冲器中,从而无须在每一次循环都反复重取相同指令。通过将循环指令保存在能够在单周期内访 问的缓冲器中,能够节省大量的周期数。该特性不需要程序员进行额外的设置,但是需要知道循环缓冲器的尺寸以合理地选择循环大小。

  高速缓冲存储器

  通常典型的DSP具有少量的快速、内置存储器。MCU通常可以访问大量的外部存储器。分层存储器体系结构将这两种方案的优点结合在一起,从而可提供几种等级具有不


同性能的存储器。对于需要最高性能应用,可以在单个核心时钟周期内访问内置SRAM。对于具有大代码尺寸的系统,可提供大量、较长等待延迟的片内和片外存储器。

  这种分层存储器体系结构本身仅仅是发挥一定的作用,由于现在的高性能处理器常常运行在较低的时钟频率下,因此大的应用程序只能装在较慢的外部存 储器中。此外,程序员被迫手动将关键代码移入和移出内部SRAM。但是,通过将数据和指令高速缓冲存储器加到该体系结构中后,外部存储器更易于管理,高速 缓冲存储器可以减少将指令和数据移入处理器内核的手工操作。由于不需要考虑进入内核的数据和指令流管理,可以大大简化编程模式。

  指令高速缓存通常采用了某种类型的最近最少使用(LRU)算法,从而确保更常用的指令代替较少使用的指令。将一些内置数据存储器配置为高速缓存 和部分SRAM的能力可以优化性能。直接存储器访问(DMA)控制器能够直接控制内核,同时当需要表中数据时将其读入数据高速缓存。一旦高速缓存允许并且 DMA控制器配置完毕,则程序员即可集中精力于内核算法的开发。

  每周期多次操作

  通常以每秒执行多少百万条指令(MIPS)来衡量处理器。曾经被保留用在高成本并行处理器中的多发布指令目前也可用在低成本、定点处理器中。除 了在每个核心处理器周期内完成多条ALU或MAC操作外,在相同周期内还可完成额外的数据处理和数据存储。存储器通常划分为子若干个存储器组,这些存储器 组可以被内核双向访问并且被DMA控制器随机访问。鉴于上述的基于硬件的寻址算法的分解方法,很明显其可以在单个周期内完成许多操作。

  图3示出多操作指令的一个实例。如图3所示,在一个周期内除了完成两条独立的MAC操作外,在相同的处理器时钟周期内还完成了数据读取和数据存储。

图3 Blackfin多发布指令在单周期内完成几次操作

  互锁流水线

  随着处理器速度的增加,从整个电路级来看处理流水线必定会变得更深。然而,有些处理器具有“互锁”流水线。这意味着当完成汇编语言编程时,程序员不必手动调度或跟踪通过流水线的数据和指令。处理器会自动处理这些时序的事情。

  灵活的数据寄存器文档

  最后,另外一个补充特性是通用数据寄存器集。在传统的定点DSP中,字长通常是固定的。然而,具有能够用作一个32bit(例如R0)或两个 16bit(例如分别用于低8bit和高8bit的R0.L和R0.H)的数据寄存器是非常有利的。在双MAC系统中,这允许在单周期内操作四个 16bit的数据。

  内积

  内积或者标量积在度量两个向量的正交性时是很有效的操作。大多数C语言程序员应该熟悉以下的内积操作:

  short dot(short a[], short b[], int size) {

   int i;

   int output = 0;

   for(i=0; i<>

   output += (a[i] * b[i]);

   }

  return output;

  下面是Blackfin处理器汇编代码的主要部分:

  //P0=loop count, I0 & P1 are address registers

  A1 = A0 = 0; // A0 & A1 are accumulators

  LSETUP (loop1,loop1) LC0 = P0 ;// Setup hardware loop starting at label loop1:

  loop1: A1 +=R1.H*R0.H, A0+=R1.L*R0.L||R1=[P1++]||R0=[I0++];

下面几点说明了简化这种紧凑编码的DSP体系结构特性。

  硬件循环缓冲器和循环计数器在每次迭代的末端不需要跳转指令。由于内积是乘积总和,因此可在一次循环中完成。该汇编程序所示是LSETUP指令,它是执行循环所需的唯一指令。

  多发布指令允许在相同的周期内执行多条指令和两次数据访问。在每一次迭代时,必须先读取a[i]和b[i]值,然后相乘,最后写回到可变输出的运行总和中。在许多MCU平台上,这实际上等于四条指令。汇编代码的最后一行示出在一个周期内可执行的所有操作。

  并行ALU操作允许同时执行两条16bit指令。汇编代码示出在每次迭代中使用的两个累加器单元(A0和A1),这将迭代次数减少了50%,从而将原来的执行时间减少了一半。

  FIR算法

  有限脉冲响应(FIR)滤波器是一种等价于卷积操作很常见的滤波器结构。A通过C操作看起来非常类似于内积。

  //将信号取样到循环缓冲器中

  x[cur] = sampling_function();

  cur = (cur+1)%TAPS; // 在循环中增加cur指针

  //完成乘加

  y = 0;

  for (k=0; k<>

   y += h[k] * x[(cur+k)%TAPS];

  }

  使用汇编语言编写的FIR内核格式有些类似于内积。在这个特定的例子中,取样值存储在R0寄存器中,同时系数存储在R1寄存器中。

  // P0 存有滤波器抽头

  R0=[I0++] || R1=[I1++]; // 设置R0和R1的初始值

  A1=A0=0; // 将累加器置零

  LSETUP (loop1, loop1) LC0 = P0;//设置内部循环

  loop1: A1+=R0.L*R1.L, A0+=R0.H*R1.H||R0=[I0++]||R1=[I1++]; //计算

  除了具有所描述的用于内积的特性外,上面所示的FIR算法也可使用循环缓冲。


  循环缓冲器不需要直接取余运算。在C代码片段中,%(取余)运算符可提供一种用于循环缓冲的机理。正如汇编内核中所示,这些取余运算符不能被编 译为内循环中的其他指令。相反,数据地址发生器寄存器I0和I1可在外循环中配置,以便在循环到达系数缓冲器边界时能够自动返回起始处。

  FFT算法

  快速傅立叶变换(FFT)是许多信号处理算法不可缺少的一部分,其特点之一是输入向量按照连续时间顺序排列,但输出按比特翻转顺序排列。大多数传统的通用处理器要求程序员用单独的程序整理比特翻转输出。在DSP平台上,比特翻转可用于寻址引擎。

  比特翻转寻址在实现FFT时不需要单独的比特翻转程序,允许硬件自动将FFT算法的输出进行比特翻转,无须程序员编写额外的程序,从而改进了性能。

  除了上面所提到的指令外,有些处理器也包括额外一套专用指令以支持多种应用。提供这些指令的目的就是进一步提高对算法的处理能力,例如维特比算法、Huffman编码以及许多其他比特操作程序。

Blackfin汇编语言之程序流程控制


Blackfin常用指令均摘录自blackfin编程参考手册,以方便查阅。

Blackfin流程控制指令有:

1. jump
2. if CC jump
3. call
4. rts, rti, rtx, rtn, rte
5. lsetup, loop

分别简介之。

* jump

General Form
JUMP (destination_indirect)
JUMP (PC + offset)
JUMP offset
JUMP.S offset
JUMP.L offset

Syntax
JUMP ( Preg ) ;
/*indirect to an absolute (not PC-relative)address(a)*/
JUMP ( PC + Preg ) ; /* PC-relative, indexed (a)*/
JUMP pcrel25m2 ; /* PC-relative, immediate (a) or (b)*/
JUMP.S pcrel13m2 ; /*PC-relative, immediate, short (a)*/
JUMP.L pcrel25m2 ; /* PC-relative, immediate, long (b)*/
JUMP user_label ;
/* user-defined absolute address label,resolved by the
assembler/linker to the appropriate PC-relative
instruction (a) or (b) */

Syntax Terminology
Preg: P5–0, SP, FP
pcrelm2: undetermined 25-bit or smaller signed, even
relative offset, with a range of –16,777,216
through 16,777,214 bytes
(0xFF00 0000 to 0x00FF FFFE)
pcrel13m2: 13-bit signed, even relative offset, with a
range of –4096 through 4094 bytes (0xF000 to
0x0FFE)
pcrel25m2: 25-bit signed, even relative offset, with a
range of –16,777,216 through 16,777,214 bytes
(0xFF00 0000 to 0x00FF FFFE)
user_label: valid assembler address label, resolved by
the assembler/linker to a valid PC-relative offset

注:1(a)16bit指令长度,(b)32bit指令长度
(bp)Branch Prediction
2。跳转地址必须偶地址对齐(16bit-address)

* if cc jump

General Form
IF CC JUMP destination
IF !CC JUMP destination

Syntax
IF CC JUMP pcrel11m2 ;
/* branch if CC=1, branch predicted as not taken (a)*/
IF CC JUMP pcrel11m2 (bp) ;
/* branch if CC=1, branch predicted as taken (a) */
IF !CC JUMP pcrel11m2 ;
/* branch if CC=0, branch predicted as not taken (a)*/
IF !CC JUMP pcrel11m2 (bp) ;
/* branch if CC=0, branch predicted as taken (a) */
IF CC JUMP user_label ;
/*user-defined absolute address label, resolved by the
assembler/linker to the appropriate PC-relative
instruction (a) */
IF CC JUMP user_label (bp) ;
/* user-defined absolute address label, resolved by the
assembler/linker to the appropriate PC-relative
instruction (a) */
IF !CC JUMP user_label ;
/* user-defined absolute address label, resolved by the
assembler/linker to the appropriate PC-relative
instruction(a) */
IF !CC JUMP user_label (bp) ;
/* user-defined absolute address label, resolved by the
assembler/linker to the appropriate PC-relative
instruction (a) */

Syntax Terminology
pcrel11m2: 11-bit signed even relative offset, with a
range of –1024 through 1022 bytes (0xFC00 to 0x03FE)
this value can optionally be replaced with an
address label that is evaluated and replaced during
linking.
user_label: valid assembler address label, resolved by
the assembler/linker to a valid PC-relative offset

* call

General Form
CALL (destination_indirect)
CALL (PC + offset)
CALL offset

Syntax
CALL ( Preg ) ;
/*indirect to an absolute (not PC-relative) address (a)*/
CALL ( PC + Preg ) ; /* PC-relative, indexed (a) */
CALL pcrel25m2 ; /* PC-relative, immediate (b) */
CALL user_label ; /*user-defined absolute address label,
resolved by the assembler/linker to the appropriate
PC-relative instruction (a) or (b) */

Syntax Terminology
Preg: P5–0, SP, FP
pcrel25m2: 25-bit signed, even, PC-relative offset; can
be specified as a symbolic address label, with a
range of –16,777,216 through 16,777,214 (0xFF00 0000
to 0x00FF FFFE) bytes.
user_label: valid assembler address label, resolved by
the assembler/linker to a valid PC-relative offset

* RTS, RTI, RTX, RTN, RTE (Return)

General Form
RTS, RTI, RTX, RTN, RTE

Syntax
RTS ; // Return from Subroutine (a)
RTI ; // Return from Interrupt (a)
RTX ; // Return from Exception (a)
RTN ; // Return from NMI (a)
RTE ; // Return from Emulation (a)

Types of Return Instruction



* LSETUP, LOOP

General Form
There are two forms of this instruction. The first is:

LOOP loop_name loop_counter
LOOP_BEGIN loop_name
LOOP_END loop_name

The second form is:

LSETUP (Begin_Loop, End_Loop)Loop_Counter

Syntax
For Loop0

LOOP loop_name LC0 ; /* (b) */
LOOP loop_name LC0 = Preg ; /*autoinitialize LC0 (b)*/
LOOP loop_name LC0 = Preg >> 1 ; /* autoinit LC0(b) */
LOOP_BEGIN loop_name ;
/* define the 1st instruction of loop(b)*/
LOOP_END loop_name ;
/* define the last instruction of the loop (b) */
/* use any one of the LOOP syntax versions with a
LOOP_BEGIN and a LOOP_END instruction. The name of the
loop (“loop_name” in the syntax) relates the three
instructions together. */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC0 ; /* (b) */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC0 = Preg ;
/* autoinitialize LC0 (b) */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC0 = Preg >> 1 ;
/* autoinitialize LC0 (b) */

For Loop1

LOOP loop_name LC1 ; /* (b) */
LOOP loop_name LC1 = Preg ; /* autoinitialize LC1 (b)*/
LOOP loop_name LC1 = Preg >> 1;/*autoinitialize LC1 (b)*/
LOOP_BEGIN loop_name ;
/* define the first instruction of the loop (b) */
LOOP_END loop_name ;
/* define the last instruction of the loop (b) */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC1 ; /* (b) */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC1 = Preg ;
/* autoinitialize LC1 (b) */
LSETUP ( pcrel5m2 , lppcrel11m2 ) LC1 = Preg >> 1 ;
/* autoinitialize LC1 (b) */

Syntax Terminology
Preg: P5?b>C0 (SP and FP are not allowed as the source
register for this instruction.)
pcrel5m2: 5-bit unsigned, even, PC-relative offset; can
be replaced by a symbolic label. The range is 4 to 30.
lppcrel11m2: 11-bit unsigned, even, PC-relative offset
for a loop; can be replaced by a symbolic label. The
range is 4 to 2046 (0x0004 to 0x07FE).
loop_name: a symbolic identifier

Blackfin包含两组寄存器用于硬件循环:
Loop_Top (LTx): LT0,LT1
Loop_Bottom (LBx): LB0,LB1
Loop_Count (LCx): LC0,LC1

2008年11月22日

Blackfin 处理器硬件设计注意事项

Blackfin 处理器硬件设计注意事项

概述:
为采用blackfin处理器设计产品的工程师避免犯一般错误。除了这个文档
之外,设计者应当读相关的规格书,硬件参考手册,以及所用处理器的堪误
表(可以从ADI网站中下载到)。

NMI极性:
所使用的处理器的双极性非屏蔽中断引脚。个别处理器(如ADSP-BF531/
BF532/BF533/BF535和BF561),NMI引脚激活为高。而其他处理器,NMI
引脚激活为低以便于同标准的外围设计连接。同样的,注意NMI引脚是否可
用以它的非激活状态。
注:不要让NMI悬空。

5V电压容许
直接将5V电压连接到引脚有可能使其损坏、产生故障。Blackfin处理器输
出连接到5V设备输入引脚可能左漂浮或可能被上拉到5V。大多数处理器引脚
不能容忍5V电压。除了两线接口(TWI)引脚。其他所有引脚电压变化应当
保证在规格书中规定的电压值或小于其许可范围的最大值,高电压中采用限
流电阻不能起到完全的保护作用。

不使用引脚处理:
看数据手册中的引脚描述列表。

信号完整性:
快速的信号上升时间和下降时间是引起信号完整性的主要问题。处理器的
每个引脚上升/下降斜率不一样。同样的,一些引脚对噪音和其他引脚的信
号反射具有更大的敏感性。采用简单的信号完整性处理方法防止线上传播反
射信号干扰时钟和同步信号,短的走线和连续终止对以下的信号很重要:
CLINK引脚应当有相应的驱动阻抗匹配。
SPORT口信号(TCLK,RCLK,RFS,TFS)应当采用终结。
PPI引脚,如PPI——CLK和同步信号也同样受益于标准的信号完整性技术。
SDRAM时钟,控制,地址和数据对连续的终于有益并减少不必要的EMI。
假如有多个信号源的信号,要保证走线短是很困难的,ADI网站上提供的
IBIS模块有助于对这些信号的处理。

测试点和信号提取:
对CLKOUT,SCLK,BANK选择,PPICLK和RESET信号设置测试点可以方便调
试。如果选择的如引导模式(BMODE)引脚直接连到电源或地,对于BGA封装
的处理器将没法做到。对于调试,使用上拉或下拉电阻比直接接电源或地更
好。

旁路电容:
对于更高速度的电路对内部供电端加上适当的旁路电容。电路中的有害感
应电容对高频电路具有很大的影响。有两件事需要考虑:当处理器运行速度
高于100MHz时,首先电容应当少,走线应当短以减小感应系数。0402的表贴
电容比更大尺寸的电容效果要明显。第二,小电容值将更容易引起LC电路的
自激。低于50MHZ的采用几个0.1uF的电容。高于500MHz的采用VDD——INT旁
0.1,0.01,0.001和100pF的组合电容。

复位:
Blackfin处理器的引脚没有滞后作用,因此,要求一个单调和上升或下降。
所以复位引脚不能直接连到R/C延时电路上,Blackfin处理器对这种电路噪
音比较敏感。所以复位引脚应当有一个复位芯片生产一个复位信号供给。

JTAG:
JTAG接口的完整应用,参考Analog Devices JTAG Emulation Technical
Reference (EE-68)[1]

PF引脚作为输出使用:
PF引脚作为输出应当接上拉或下拉以确定复位时的状态。

使用EZ-KIT Lite原理图
EZ-KIT Lite评估系统的原理图是一个很好的设计参考。因为EZ-KIT Lite
是一个评估和开发板,还提供一些例子

总线请求:
总线请求引脚(/BR)要求在所有的设计中加上拉电阻。如果不加上拉电阻
在没有任何外设驱动的情况下可能产生错误的总线请求。

Blackfin汇编语言之程序调用接口

ABI(Application Binary Interface)定义了应用程序和操作系统之间或函数之间在堆栈使用、参数传递以及寄存器使用上的规则,只有大家都遵守这个规则,不同的代码才可以无差错的链接到一起完成某项任务。
1。数据存储格式
BF532使用的是小端字节序。所以数据在寄存器和内存中的存储形式是:
2。寄存器使用约定
  • 专用寄存器
P6 -- SP Stack Pointer register
P7 -- FP Frame Pointer register
这两个寄存器都是固定给编译器使用的,要求4-bytes字节对齐,且必须位于适当的堆栈内存区域内

L0-L3 -- 循环长度寄存器,要求假定L0-L3寄存器的值为0,也就是说在调用函数和退出函数之前要将寄存器归零
  • 函数调用需维护的寄存器
下面这几个寄存器如果函数中需要使用到则需要在使用之前保存寄存器值,并且在函数退出之前恢复寄存器原值。
P3--P5
R4--R7
  • 函数中可以任意使用的寄存器
  1. P0 用作返回地址寄存器
  2. P1–P2
  3. R0 - R3 R0,R1,R2用作函数参数传递寄存器,R3不用作参数传递
  4. LB0–LB1
  5. LC0–LC1
  6. LT0–LT1
  7. ASTAT (Including CC)
  8. A0–A1
  9. I0–I3
  10. B0–B3
  11. M0–M3
调用函数执行顺序:
  • 栈帧指针设置。在栈保存返回地址和调用函数的FP寄存器值。设置FP寄存器值为被调用函数的栈帧地址。SP指针地址递减从而分配本地变量和编译器使用临时的内存空间。
  • 保存函数调用约定需要维护的寄存器的值;SP寄存器指向栈帧的顶部。
退出函数执行顺序:
  • 恢复函数调用约定需要维护的寄存器的值;SP寄存器指向栈帧的顶部。
  • 栈帧指针回退。FP回复为调用函数的栈帧地址;RETS设置为返回地址;SP设置为调用函数栈帧的顶部地址。
例如:
进入被调用函数:
  LINK       16;
[--SP]=(R7:4);
SP + = –16;
[FP+8]=R0; [FP+12]=R1; [FP+16]=R2;
  • LINK 16;是一条特殊的链接指令,它保存返回地址和栈帧指针FP,并在堆栈SP上分配16bytes空间给本地变量使用
  • [--SP]=(R7:4); 分配空间并保存寄存器的值
  • SP += -16; 分配空间给传出参数使用,至少为12bytes。
  • [FP+8]=R0; [FP+12]=R1; [FP+16]=R2; 保存函数参数值
退出被调用函数:
   SP + = 16;
P0=[FP+4];
(R7:4)=[SP++];
UNLINK;
JUMP (P0);
  • SP += 16;恢复SP指针
  • P0=[FP+4]; 将返回地址设置到P0寄存器
  • (R7:4)=[SP++]; 恢复保存寄存器的值
  • UNLINK; 特殊指令,恢复SP和FP指针
  • JUMP (P0); 返回函数调用之处继续执行

LINK 这条指令做了如下工作:
[--SP] = RETS;
[--SP] = FP;
FP = SP;
SP += -n;
也就是说,在每个函数的开头,首先都保存了本函数的返回地址,同时还保存了上一个调用函数的FP指针。实际上就相当于把函数的返回地址用一个单链表链接起来,只要顺着这个链表往上找,自然就可以找出调用函数的返回地址了。

2008年11月18日

BF532 176 Pin LQFP IBIS Model

估计是ADI把文件名字弄错了。

ADSP-BF531/BF532/BF533 2.5/3.3 V I/O Blackfin Processor IBIS Datafile 160-Ball CSP BGA Package (09/2005)

TMS320DM642 SDRAM PCB预仿真

最近在调试SDRAM电路正需要这样实用的文章,转载至此。TMS320DM642 SDRAM PCB预仿真

现在国内几乎所有的电子企业都不做PCB仿真,画完PCB直接投入生产,即使高频应用经验丰富的工程师也难免会出差错。因为很多情况下都要对一些方案进行折衷。就像这款JD642,体积较小,64位的SDRAM数据线如果加匹配处理的话需要很多空间,而如果不做匹配的话又怕信号质量不能满足要求。怎么折衷?不加匹配,等出现信号质量问题再改版吗?成本?开发周期?...即使调试过程中没有发现信号质量问题,以后产品投入市场能确保没有问题吗?下面就通过SDRAM数据线PCB信号仿真来看一下如何利用PCB仿真工具来协助完成原理图设计。

应用情景
  下面是一个DSP硬件电路部分元件位置关系(原理图和PCB使用PROTEL99SE设计),其中DRAM作为DSP的扩展Memory(64位宽度,低8bit还经过3245接到FLASH和其它芯片)DRAM时钟频率133M。因为频率较高,设计过程中我们需要考虑DRAM的数据、地址和控制线是否需加串阻。下面,我们以数据线D0仿真为例看是否需要加串阻。





模型建立
  首先需要在元件公司网站下载各器件IBIS模型。
  然后打开Hyperlynx,新建LineSim File(线路仿真主要用于PCB前仿真验证)



  新建好的线路仿真文件里可以看到一些虚线勾出的传输线、芯片脚、始端串阻和上下拉终端匹配电阻等。
  下面,我们开始导入主芯片DSP的数据线D0脚模型。
左键点芯片管脚处的标志,出现未知管脚,然后再按下图的红线所示线路选取芯片IBIS模型中的对应管脚。



  


OK后退到“ASSIGN Models”界面。选管脚为“Output”类型。
  这样,一样管脚的配置就完成了。同样将DRAM的数据线对应管脚和3245的对应管脚IBIS模型加上(DSP输出,3245高阻,DRAM输入)




  

下面我们开始建立传输线模型。
  左键点DSP芯片脚相连的传输线,增添传输线,然后右键编辑属性。因为我们使用四层板,在表层走线,所以要选用“Microstrip”,然后点“Value”进行属性编辑。这里,我们要编辑一些PCB的属性,布线长度、宽度和层间距等,属性编辑界面如下:




  

再将其它传输线也添加上。




  

这就是没有加阻抗匹配的仿真模型(PCB最远直线间距1.4inch,对线长为1.7inch)。现在模型就建立好了。

仿真及分析
  下面我们就要为各点加示波器探头了,按照下图红线所示路径为各测试点增加探头:




  

为发现更多的信息,我们使用眼图观察。因为时钟是133M,数据单沿采样,数据翻转最高频率为66.7M,对应位宽为7.58ns。所以设置参数如下:




  

之后按照芯片手册制作眼图模板。因为我们最关心的是接收端(DRAM)信号,所以模板也按照DRAM芯片HY57V283220手册的输入需求设计。

  芯片手册中要求输入高电平VIH高于2.0V,输入低电平VIL低于0.8VDRAM芯片的一个NOTE里指出,芯片可以承受最高5.6V,最低-2.0V信号(不长于3ns)




  

按下边红线路径配置眼图模板:





  

之后就可以进行仿真了,来看一下我们的眼图吧:)




  

可以看到三个测试点波形差异很大。波形最差的就是接收端的紫色波开形了,上冲到5.4V,下冲到-1.2V。但仍能满足DRAM芯片要求。从DRAM芯片方面来看,不加串阻是可以满足芯片要求的,而且接收端的信号虽然回冲很大,不过,还是高于2.0V,满足芯片高电平界定标准。整个眼图和模板没有交叠,所以可以接受。

  下面再看一下在DRAM侧距DSP引脚500mil的地方加33欧串阻的话信号是什么样子:




  

可以看到信号质量明显改善。上下冲和回冲都减小了。

  我们知道匹配分始端串联匹配和终端并联匹配。那看一下终端并75欧电阻波形是什么样子:




  

波形也明显改善很多^_^

  当然,始端串阻和终端并阻是不能同时使用的,如果同时使用,对终端实际上就形成了分压。最终电平不能满足高电平判别需求:




  

上图是在始端加33欧串阻,终端加75欧并阻的情况,可以看到DRAM接收到的高电平只有3*(75/(75+33))2V

  对于这样的数据总线,随着读和写的改变,始端和末端也发生变化,那样串阻就不好确定放在什么地方了,那我们看一下,把串阻放在靠近DRAM端的情况(DSP1.2inch,距DRAM0.5inch)





  

可见,效果仍然比不加串阻的情况要好很多,之所以串阻能起到这样的效果。从能量的角度可以简单的这样理解,因为整条线的各个芯片脚都是阻抗比较大,整条线上没有消耗能量的点,没有串阻的话,能量会在传输线上来回反射,相互叠加,造成很大的过冲和振铃。其中又因为DRAM输入阻抗较高,而且线又较长,所以信号问题比较严重。在这段线上加一个串阻能有效的消耗反射的能量,使过冲和振铃现象得到改善。

  下面我们再把DRAM设为输出端,DSP设为输入端,3245仍为高阻,看一下各点的测试波形。




  

看一下是否能满足DSP芯片要求

  在DSP芯片数据手册里有下面一段内容:





  

这段内容指出,下冲不低于-1.0V,上冲不超过4.3V就算合格的。这样看来DSP也可以接受不加串阻的情况。而3245数据手册没有给出芯片输入电平条件,但从芯片资料给出的内部结构上看,输入电平高于4V是没有问题的。

结论
  低8位数据线没有串阻可以满足设计要求,而其他的56位都是一对一,经过仿真没有串阻也能通过。于是数据线不加串阻可以满足设计要求,但有一点需注意,就是写数据时因为存在回冲,DRAM接收高电平在位中间会回冲到2V。因此会导致电平判决裕量较小,抗干扰能力差一些,如果调试过程中发现写RAM会出错,还需要改版加串阻(单板调试时SDRAM经超频测试到150M系统运行稳定,长时间通过CCS观察SDRAM内数据没有发现错误数据)。


  一些朋友怀疑软件仿真的可靠性,其实软件仿真不管是原理图仿真还是PCB仿真,关键是模型提取和建立。只要模型建立正确,仿真结果还是很可靠的(以前用250M信号验证过CADENCEHyperlynx的仿真结果,示波器观察到的波形和仿真结果还是很一致的)。至于人们说的误差确实也是存在的,比如PCB板阻抗由于材质差异及厚度差异、温度变化、信号频率差异等可能存在20%左右的误差。即使这些差异存在,但仿真结果仍然具有极高的参考意义,掌握一定的高频应用知识和材料知识可以帮我们更好的利用仿真结果做出最佳的决策。