FPGA / ARM / DSP Wishbone SoC
< Using GNUARM >
Lab1 : Wishbone0
ARM SoC / FPGA Wishbone Bus 整合實驗1
▋Introduction
Lab.1是一個整合ARM SoC與FPGA硬體的範例。FPGA部分為個Wishbone SoC Bus System Wishbone0包含Wishbone Bus Framework,一個ARM9 Interface Master及一個簡單的GPIO Slave。實驗以ARM執行一段程式,控制GPIO Slave驅動之LED。
ARM的程式是在Windows環境中,以GNUARM Compiler進行編譯,並以ARM模組的UBoot提供之命令直接載入記憶體執行。
▋Design Codes
在此實驗FPGA內的Wishbone0電路架構可分成三部分: Wishbone Bus Framework, Wishbone ARM Master及一個簡單的Wishbone GPIO Slave。
wbbus8n8.v是一個最多可容納8個Master和8個Slave的一個shared bus架構的Wishbone Bus Framework,而沒有用到的Master和Slave Ports則連接到一個不使用並安全的狀態。 wbbus8n8.v內包還含一個Wishbone 的Master arbiter wbarb8.v,負責決定8個可能的Master,何者可以開始一個讀或寫的bus transaction。連接ARM9 SoC與Wishbone 的ARM Master Wrapper為Wishbone0的唯一Master。wbios.v則是一個簡單的具GPIO Wishbone Slave.
▋Hierarchy
wbchip.v
`timescale 1ns / 100ps
module wbchip
(
mclk,
mrsti,mrstg,
ledo,
dpswi,
aadr,adt,
agcs2,anwe,anoe,
awbe,
anwt
);
input mclk;
input mrsti;
output mrstg;
output[23:0] ledo;
input[7:0] dpswi;
input[24:2] aadr;
inout[31:0] adt;
input agcs2;
input anwe,anoe;
input[3:0] awbe;
output anwt;
parameter cmdw=32+32+4+1+3+2+1+1;
// addr+wdata+sel+we+cti+bte+stb+cyc
parameter rtnw=32+1+1+1;
// rdata+err+rty+ack
wire[31:0] ardt;
wire[31:0] m0_wbadr;
wire[31:0] m0_wbwdt;
wire[3:0] m0_wbsel;
wire m0_wbwe;
wire[2:0] m0_wbcti;
wire[1:0] m0_wbbte;
wire m0_wbcyc;
wire m0_wbstb;
wire[31:0] m0_wbrdt;
wire m0_wberr;
wire m0_wbrty;
wire m0_wback;
wire[31:0] s0_wbadr;
wire[31:0] s0_wbwdt;
wire[3:0] s0_wbsel;
wire s0_wbwe;
wire[2:0] s0_wbcti;
wire[1:0] s0_wbbte;
wire s0_wbcyc;
wire s0_wbstb;
wire[31:0] s0_wbrdt;
wire s0_wberr;
wire s0_wbrty;
wire s0_wback;
wire mrst=~mrsti;
assign mrstg=1'b0;
assign m0_wbcti='b010,m0_wbbte='b00;
// addr+wdata+sel+we+cti+bte+stb+cyc
wbbus8n8 wbbus(
.mclk(mclk),.mrst(mrst),
.m0_cmdi({m0_wbadr,m0_wbwdt,m0_wbsel,m0_wbwe,
m0_wbcti,m0_wbbte,m0_wbstb,m0_wbcyc}),
.m0_rtno({m0_wbrdt,m0_wberr,m0_wbrty,m0_wback}),
.m1_cmdi({(cmdw){1'b0}}),
.m1_rtno(),
.m2_cmdi({(cmdw){1'b0}}),
.m2_rtno(),
.m3_cmdi({(cmdw){1'b0}}),
.m3_rtno(),
.m4_cmdi({(cmdw){1'b0}}),
.m4_rtno(),
.m5_cmdi({(cmdw){1'b0}}),
.m5_rtno(),
.m6_cmdi({(cmdw){1'b0}}),
.m6_rtno(),
.m7_cmdi({(cmdw){1'b0}}),
.m7_rtno(),
.s0_cmdo({s0_wbadr,s0_wbwdt,s0_wbsel,s0_wbwe,
s0_wbcti,s0_wbbte,s0_wbstb,s0_wbcyc}),
.s0_rtni({s0_wbrdt,s0_wberr,s0_wbrty,s0_wback}),
.s1_cmdo(),
.s1_rtni(1),
.s2_cmdo(),
.s2_rtni(1),
.s3_cmdo(),
.s3_rtni(1),
.s4_cmdo(),
.s4_rtni(1),
.s5_cmdo(),
.s5_rtni(1),
.s6_cmdo(),
.s6_rtni(1),
.s7_cmdo(),
.s7_rtni(1)
);
assign adt=(~anoe&~agcs2)?ardt:32'bz;
wb_arm wb_arm(
.mclk(mclk),
.mrst(mrst),
.aadr(aadr),
.awdt(adt),
.ardt(ardt),
.agcs2(agcs2),
.anwe(anwe),
.anoe(anoe),
.awbe(awbe),
.anwt(anwt),
.wbadr (m0_wbadr),
.wbdin (m0_wbrdt),
.wbdout(m0_wbwdt),
.wbcyc (m0_wbcyc),
.wbstb (m0_wbstb),
.wbsel (m0_wbsel),
.wbwe (m0_wbwe),
.wback (m0_wback),
.wberr (m0_wberr),
.wbrty (m0_wbrty)
);
wbios wbios
(
.mclk(mclk),
.mrst(mrst),
.ledo(ledo),
.dpswi(dpswi),
.wbadr (s0_wbadr),
.wbdin (s0_wbwdt),
.wbdout(s0_wbrdt),
.wbcyc (s0_wbcyc),
.wbstb (s0_wbstb),
.wbsel (s0_wbsel),
.wbwe (s0_wbwe),
.wback (s0_wback),
.wberr (s0_wberr),
.wbrty (s0_wbrty)
);
endmodule
wb_arm.v
`timescale 1ns / 100ps
module wb_arm(
mclk, mrst,
aadr,
awdt,
ardt,
agcs2,
anwe,
anoe,
awbe,
anwt,
wbadr,
wbdin,
wbdout,
wbcyc,wbstb,
wbsel,
wbwe,
wback,wberr,wbrty
);
input mclk,mrst;
input[24:2] aadr;
input[31:0] awdt;
output[31:0] ardt;
input agcs2;
input anwe,anoe;
input[3:0] awbe;
output anwt;
output[31:0] wbadr;
input[31:0] wbdin;
output[31:0] wbdout;
output wbcyc,wbstb;
output[3:0] wbsel;
output wbwe;
input wback,wberr,wbrty;
reg[31:0] wbadr;
reg[31:0] wbdout;
reg[3:0] wbsel;
reg mwes,moes;
reg[1:0] macss,nmacss;
reg wbcyc,wbstb;
reg[31:0] ardt;
always @(posedge mclk)
begin
wbadr<={7'b0,aadr[24:2],2'b0};
wbdout<=awdt;
wbsel<=~awbe;
mwes<=~anwe&~agcs2;
moes<=~anoe&~agcs2;
end
always @(posedge mclk or posedge mrst)
begin
if(mrst) macss<=2'b00;
else macss<=nmacss;
end
always @(macss or mwes or moes or wback)
begin
case(macss)
2'b00: begin wbcyc=(mwes|moes); wbstb=(mwes|moes);
nmacss=((mwes|moes)&wback)?'b01:'b00; end
2'b01: begin wbcyc=1'b0; wbstb=1'b0;
nmacss=((~mwes&~moes)?'b00:'b01); end
default: begin wbcyc=1'b0; wbstb=1'b0;
nmacss=2'b00; end
endcase
end
//// wb signals
assign wbwe=mwes;
//// arm signals
always@(posedge mclk)
begin
ardt<=(wbstb&wback)?wbdin:ardt;
end
/*
always@(wbdin)
begin
ardt=wbdin;
end
*/
assign anwt=~((mwes|moes)&~macss[0]);
endmodule
wbios.v
`timescale 1ns / 100ps
module wbios
(
mclk, mrst,
ledo,
dpswi,
wbadr,
wbdin,
wbdout,
wbcyc,wbstb,
wbsel,
wbwe,
wback,wberr,wbrty
);
input mclk,mrst;
output[23:0] ledo;
input[7:0] dpswi;
input[31:0] wbadr;
input[31:0] wbdin;
output[31:0] wbdout;
input wbcyc,wbstb;
input[3:0] wbsel;
input wbwe;
output wback,wberr,wbrty;
reg[31:0] wbdout;
reg[23:0] ledo;
assign wback=wbcyc&wbstb;
assign wberr=1'b0;
assign wbrty=1'b0;
always @*
begin
case(wbadr[7:2])
('h04>>2): wbdout={24'b0,dpswi};
default: wbdout=32'b0;
endcase
end
always @(posedge mclk or posedge mrst)
begin
if(mrst) begin
ledo<=24'b0;
end
else if(wbcyc&wbstb&wbwe) begin
case(wbadr[7:2])
('h000>>2): begin
if(wbsel[2]) ledo[23:16]<=wbdin[23:16];
if(wbsel[1]) ledo[15: 8]<=wbdin[15: 8];
if(wbsel[0]) ledo[ 7: 0]<=wbdin[ 7: 0]; end
endcase end
end
endmodule
wbbus8n8.v
`timescale 1ns / 100ps
module wbbus8n8(
mclk, mrst,
m0_cmdi,m0_rtno,
m1_cmdi,m1_rtno,
m2_cmdi,m2_rtno,
m3_cmdi,m3_rtno,
m4_cmdi,m4_rtno,
m5_cmdi,m5_rtno,
m6_cmdi,m6_rtno,
m7_cmdi,m7_rtno,
s0_rtni,s0_cmdo,
s1_rtni,s1_cmdo,
s2_rtni,s2_cmdo,
s3_rtni,s3_cmdo,
s4_rtni,s4_cmdo,
s5_rtni,s5_cmdo,
s6_rtni,s6_cmdo,
s7_rtni,s7_cmdo
);
parameter cmdw=32+32+4+1+3+2+1+1; // addr+wdata+sel+we+cti+bte+stb+cyc
parameter rtnw=32+1+1+1; // rdata+err+rty+ack
parameter adcw=25+32+4+1+3+2+1+1; // addr+wdata+sel+we+cti+bte+stb+cyc
// a[24:20]
parameter s0_addrw = 5, s0_addr = 5'h00;
parameter s1_addrw = 5, s1_addr = 5'h01;
parameter s2_addrw = 5, s2_addr = 5'h02;
parameter s3_addrw = 5, s3_addr = 5'h03;
parameter s4_addrw = 5, s4_addr = 5'h04;
parameter s5_addrw = 5, s5_addr = 5'h05;
parameter s6_addrw = 5, s6_addr = 5'h06;
parameter s7_addrw = 5, s7_addr = 5'h07;
input mclk, mrst;
input[cmdw-1:0] m0_cmdi, m1_cmdi, m2_cmdi, m3_cmdi, m4_cmdi, m5_cmdi, m6_cmdi, m7_cmdi;
output[cmdw-1:0] s0_cmdo, s1_cmdo, s2_cmdo, s3_cmdo, s4_cmdo, s5_cmdo, s6_cmdo, s7_cmdo;
input [rtnw-1:0] s0_rtni, s1_rtni, s2_rtni, s3_rtni, s4_rtni, s5_rtni, s6_rtni, s7_rtni;
output[rtnw-1:0] m0_rtno, m1_rtno, m2_rtno, m3_rtno, m4_rtno, m5_rtno, m6_rtno, m7_rtno;
wire[7:0] mgnt;
wire[7:0] ss_dec;
reg[cmdw-1:0] mm_cmd;
reg[rtnw-1:0] ss_rtn;
//{s0_wbrdt,s0_wberr,s0_wbrty,s0_wback}
always @*
begin
casex(ss_dec) // synthesis parallel_case full_case
8'bxxxxxxx1 : ss_rtn=s0_rtni;
8'bxxxxxx1x : ss_rtn=s1_rtni;
8'bxxxxx1xx : ss_rtn=s2_rtni;
8'bxxxx1xxx : ss_rtn=s3_rtni;
8'bxxx1xxxx : ss_rtn=s4_rtni;
8'bxx1xxxxx : ss_rtn=s5_rtni;
8'bx1xxxxxx : ss_rtn=s6_rtni;
8'b1xxxxxxx : ss_rtn=s7_rtni;
default: ss_rtn=1;
endcase
end
wbarb8 wbarb(
.mclk(mclk), .mrst(mrst),
.mreq({ m7_cmdi[0],
m6_cmdi[0],
m5_cmdi[0],
m4_cmdi[0],
m3_cmdi[0],
m2_cmdi[0],
m1_cmdi[0],
m0_cmdi[0]}),
.mgnt(mgnt)
);
//{m0_adr_i,m0_sel_i,m0_dat_i,m0_we_i,m0_cti,m0_bte,m0_stb_i,m0_cyc_i};
always @*
begin
casex(mgnt) // synthesis parallel_case full_case
8'bxxxxxxx1 : mm_cmd=m0_cmdi;
8'bxxxxxx1x : mm_cmd=m1_cmdi;
8'bxxxxx1xx : mm_cmd=m2_cmdi;
8'bxxxx1xxx : mm_cmd=m3_cmdi;
8'bxxx1xxxx : mm_cmd=m4_cmdi;
8'bxx1xxxxx : mm_cmd=m5_cmdi;
8'bx1xxxxxx : mm_cmd=m6_cmdi;
8'b1xxxxxxx : mm_cmd=m7_cmdi;
default: mm_cmd=0;
endcase
end
assign ss_dec[0]=(mm_cmd[adcw-1:adcw-s0_addrw] == s0_addr);
assign ss_dec[1]=(mm_cmd[adcw-1:adcw-s1_addrw] == s1_addr);
assign ss_dec[2]=(mm_cmd[adcw-1:adcw-s2_addrw] == s2_addr);
assign ss_dec[3]=(mm_cmd[adcw-1:adcw-s3_addrw] == s3_addr);
assign ss_dec[4]=(mm_cmd[adcw-1:adcw-s4_addrw] == s4_addr);
assign ss_dec[5]=(mm_cmd[adcw-1:adcw-s5_addrw] == s5_addr);
assign ss_dec[6]=(mm_cmd[adcw-1:adcw-s6_addrw] == s6_addr);
assign ss_dec[7]=(mm_cmd[adcw-1:adcw-s7_addrw] == s7_addr);
assign m0_rtno={ss_rtn[rtnw-1:3],mgnt[0]?ss_rtn[2:0]:3'b0};
assign m1_rtno={ss_rtn[rtnw-1:3],mgnt[1]?ss_rtn[2:0]:3'b0};
assign m2_rtno={ss_rtn[rtnw-1:3],mgnt[2]?ss_rtn[2:0]:3'b0};
assign m3_rtno={ss_rtn[rtnw-1:3],mgnt[3]?ss_rtn[2:0]:3'b0};
assign m4_rtno={ss_rtn[rtnw-1:3],mgnt[4]?ss_rtn[2:0]:3'b0};
assign m5_rtno={ss_rtn[rtnw-1:3],mgnt[5]?ss_rtn[2:0]:3'b0};
assign m6_rtno={ss_rtn[rtnw-1:3],mgnt[6]?ss_rtn[2:0]:3'b0};
assign m7_rtno={ss_rtn[rtnw-1:3],mgnt[7]?ss_rtn[2:0]:3'b0};
assign s0_cmdo={mm_cmd[cmdw-1:2],ss_dec[0]?mm_cmd[1:0]:2'b0};
assign s1_cmdo={mm_cmd[cmdw-1:2],ss_dec[1]?mm_cmd[1:0]:2'b0};
assign s2_cmdo={mm_cmd[cmdw-1:2],ss_dec[2]?mm_cmd[1:0]:2'b0};
assign s3_cmdo={mm_cmd[cmdw-1:2],ss_dec[3]?mm_cmd[1:0]:2'b0};
assign s4_cmdo={mm_cmd[cmdw-1:2],ss_dec[4]?mm_cmd[1:0]:2'b0};
assign s5_cmdo={mm_cmd[cmdw-1:2],ss_dec[5]?mm_cmd[1:0]:2'b0};
assign s6_cmdo={mm_cmd[cmdw-1:2],ss_dec[6]?mm_cmd[1:0]:2'b0};
assign s7_cmdo={mm_cmd[cmdw-1:2],ss_dec[7]?mm_cmd[1:0]:2'b0};
endmodule
wbarb8.v
`timescale 1ns / 100ps
module wbarb8
(
mclk, mrst,
mreq,
mgnt
);
input mclk;
input mrst;
input [7:0] mreq;
output [7:0] mgnt;
reg[7:0] msta,nmsta;
reg[7:0] mgnt,mgnts;
reg[7:0] mgcnt;
reg mfsw;
wire mrqe;
assign mrqe=((mgnt&mreq)=='b0);
always @(posedge mclk or posedge mrst)
begin
if(mrst) mfsw<=1'b0;
else mfsw<=(mgcnt=='h40);
end
always@(posedge mclk or posedge mrst)
begin
if(mrst) mgcnt<=0;
else if(~(mgnts==mgnt)|mrqe) mgcnt<=0;
else mgcnt<=mgcnt+1;
end
always@(posedge mclk or posedge mrst)
begin
if(mrst) begin msta<=1; mgnt<=0; mgnts<=0; end
else begin
msta<=mrqe?nmsta:msta;
mgnt<=mfsw?0:mrqe?nmsta:mgnt;
mgnts<=mgnt;
end
end
always @*
begin
casex(msta) // synthesis parallel_case full_case
8'bxxxxxxx1 : begin nmsta=mreq[7]?1<<7:mreq[6]?1<<6:mreq[5]?1<<5:mreq[4]?1<<4
:mreq[3]?1<<3:mreq[2]?1<<2:mreq[1]?1<<1:1<<0; end
8'bxxxxxx1x : begin nmsta=mreq[6]?1<<6:mreq[5]?1<<5:mreq[4]?1<<4:mreq[3]?1<<3
:mreq[2]?1<<2:mreq[1]?1<<1:mreq[0]?1<<0:1<<7; end
8'bxxxxx1xx : begin nmsta=mreq[5]?1<<5:mreq[4]?1<<4:mreq[3]?1<<3:mreq[2]?1<<2
:mreq[1]?1<<1:mreq[0]?1<<0:mreq[7]?1<<7:1<<6; end
8'bxxxx1xxx : begin nmsta=mreq[4]?1<<4:mreq[3]?1<<3:mreq[2]?1<<2:mreq[1]?1<<1
:mreq[0]?1<<0:mreq[7]?1<<7:mreq[6]?1<<6:1<<5; end
8'bxxx1xxxx : begin nmsta=mreq[3]?1<<3:mreq[2]?1<<2:mreq[1]?1<<1:mreq[0]?1<<0
:mreq[7]?1<<7:mreq[6]?1<<6:mreq[5]?1<<5:1<<4; end
8'bxx1xxxxx : begin nmsta=mreq[2]?1<<2:mreq[1]?1<<1:mreq[0]?1<<0:mreq[7]?1<<7
:mreq[6]?1<<6:mreq[5]?1<<5:mreq[4]?1<<4:1<<3; end
8'bx1xxxxxx : begin nmsta=mreq[1]?1<<1:mreq[0]?1<<0:mreq[7]?1<<7:mreq[6]?1<<6
:mreq[5]?1<<5:mreq[4]?1<<4:mreq[3]?1<<3:1<<2; end
8'b1xxxxxxx : begin nmsta=mreq[0]?1<<0:mreq[7]?1<<7:mreq[6]?1<<6:mreq[5]?1<<5
:mreq[4]?1<<4:mreq[3]?1<<3:mreq[2]?1<<2:1<<1; end
default : begin nmsta=1<<0; end
endcase
end
endmodule
▋ARM9 C Programs : gatest00
這個測試程式指透過UART在Hyperterm上顯示一字串, ARM並未在Wishbone上發出讀或寫的trnasactions. 目的只是驗證編譯工具與程式下載機制.
gatest00.c
#include <stdio.h>
#include <serial.h>
int main()
{
void (*prst)(void)=0;
serial_puts ("************* Hello World !!! *************");
(*prst)(); // reset
return 0;
}
serial.c
#include "serial.h"
/*
* Read a single byte from the serial port. Returns 1 on success, 0
* otherwise. When the function is succesfull, the character read is
* written into its argument c.
*/
int serial_getc (void)
{
S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
/* wait for character to arrive */
while (!(uart->UTRSTAT & 0x1));
return uart->URXH & 0xff;
}
/*
* Output a single byte to the serial port.
*/
void serial_putc (const char c)
{
S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
/* wait for room in the tx FIFO */
while (!(uart->UTRSTAT & 0x2));
uart->UTXH = c;
/* If \n, also do \r */
if (c == '\n')
serial_putc ('\r');
}
/*
* Test whether a character is in the RX buffer
*/
int serial_tstc (void)
{
S3C24X0_UART * const uart = S3C24X0_GetBase_UART(UART_NR);
return uart->UTRSTAT & 0x1;
}
void serial_puts (const char *s)
{
while (*s) {
serial_putc (*s++);
}
}
serial.h
typedef enum {
S3C24X0_UART0,
S3C24X0_UART1,
S3C24X0_UART2
} S3C24X0_UARTS_NR;
#define S3C24X0_UART_BASE 0x50000000
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long ulong;
typedef volatile u8 S3C24X0_REG8;
typedef volatile u16 S3C24X0_REG16;
typedef volatile u32 S3C24X0_REG32;
#define UART_NR S3C24X0_UART0
/* UART (see manual chapter 11) */
typedef struct {
S3C24X0_REG32 ULCON;
S3C24X0_REG32 UCON;
S3C24X0_REG32 UFCON;
S3C24X0_REG32 UMCON;
S3C24X0_REG32 UTRSTAT;
S3C24X0_REG32 UERSTAT;
S3C24X0_REG32 UFSTAT;
S3C24X0_REG32 UMSTAT;
S3C24X0_REG8 UTXH;
S3C24X0_REG8 res1[3];
S3C24X0_REG8 URXH;
S3C24X0_REG8 res2[3];
S3C24X0_REG32 UBRDIV;
} /*__attribute__((__packed__))*/ S3C24X0_UART;
static inline S3C24X0_UART * const S3C24X0_GetBase_UART(S3C24X0_UARTS_NR nr)
{
return (S3C24X0_UART * const)(S3C24X0_UART_BASE + (nr * 0x4000));
}
crt.s
.set MISCCR ,0x56000080
/*Miscellaneous control */
.set DCKCON ,0x56000084
/*DCLK0/1 control */
.set EXTINT0 ,0x56000088
/*External interrupt control register 0 */
.set EXTINT1 ,0x5600008c
/*External interrupt control register 1 */
.set EXTINT2 ,0x56000090
/*External interrupt control register 2 */
.set EINTFLT0 ,0x56000094
/*Reserved */
.set EINTFLT1 ,0x56000098
/*Reserved */
.set EINTFLT2 ,0x5600009c
/*External interrupt filter control register 2 */
.set EINTFLT3 ,0x560000a0
/*External interrupt filter control register 3 */
.set EINTMASK ,0x560000a4
/*External interrupt mask */
.set EINTPEND ,0x560000a8
/*External interrupt pending */
.set GSTATUS0 ,0x560000ac
/*External pin status */
.set GSTATUS1 ,0x560000b0
/*Chip ID(0x32410000) */
.set GSTATUS2 ,0x560000b4
/*Reset type */
.set GSTATUS3 ,0x560000b8
/*Saved data0(32-bit) before entering POWER_OFF mode*/
.set GSTATUS4 ,0x560000bc
/*Saved data1(32-bit) before entering POWER_OFF mode*/
.set WTCON ,0x53000000
.set INTSUBMSK ,0x4a00001c
.set INTMSK ,0x4a000008
.set LOCKTIME ,0x4c000000 /*PLL lock time counter */
.set MPLLCON ,0x4c000004 /*MPLL Control */
.set UPLLCON ,0x4c000008 /*UPLL Control */
.set CLKCON ,0x4c00000c /*Clock generator control */
.set CLKSLOW ,0x4c000010 /*Slow clock control */
.set CLKDIVN ,0x4c000014 /*Clock divider control */
.set BWSCON ,0x48000000 /*Bus width & wait status */
.set BANKCON0 ,0x48000004 /*Boot ROM control */
.set BANKCON1 ,0x48000008 /*BANK1 control */
.set BANKCON2 ,0x4800000c /*BANK2 cControl */
.set BANKCON3 ,0x48000010 /*BANK3 control */
.set BANKCON4 ,0x48000014 /*BANK4 control */
.set BANKCON5 ,0x48000018 /*BANK5 control */
.set BANKCON6 ,0x4800001c /*BANK6 control */
.set BANKCON7 ,0x48000020 /*BANK7 control */
.set REFRESH ,0x48000024 /*DRAM/SDRAM refresh */
.set BANKSIZE ,0x48000028 /*Flexible Bank Size */
.set MRSRB6 ,0x4800002c /*Mode register set for SDRAM */
.set MRSRB7 ,0x48000030 /*Mode register set for SDRAM */
/*FCLK = 176000000 */
.set M_MDIV ,105 /*Fin=12.0MHz Fout=176.0MHz */
.set M_PDIV ,2
.set M_SDIV ,2
.set DW8 , (0x0)
.set DW16 , (0x1)
.set DW32 , (0x2)
.set WAIT , (0x1<<2)
.set UBLB , (0x1<<3)
.set B1_BWSCON , (DW32)
.set B2_BWSCON , (DW32)
.set B3_BWSCON , (DW32)
.set B4_BWSCON , (DW32)
.set B5_BWSCON , (DW32)
.set B6_BWSCON , (DW32)
.set B7_BWSCON , (DW32)
.set B0_Tacs ,0x3
.set B0_Tcos ,0x3
.set B0_Tacc ,0x7
.set B0_Tcoh ,0x3
.set B0_Tah ,0x3
.set B0_Tacp ,0x3
.set B0_PMC ,0x0
.set B1_Tacs ,0x3
.set B1_Tcos ,0x3
.set B1_Tacc ,0x7
.set B1_Tcoh ,0x3
.set B1_Tah ,0x3
.set B1_Tacp ,0x3
.set B1_PMC ,0x0
.set B2_Tacs ,0x3
.set B2_Tcos ,0x3
.set B2_Tacc ,0x7
.set B2_Tcoh ,0x3
.set B2_Tah ,0x3
.set B2_Tacp ,0x3
.set B2_PMC ,0x0
.set B3_Tacs ,0x3
.set B3_Tcos ,0x3
.set B3_Tacc ,0x7
.set B3_Tcoh ,0x3
.set B3_Tah ,0x3
.set B3_Tacp ,0x3
.set B3_PMC ,0x0
.set B4_Tacs ,0x3
.set B4_Tcos ,0x3
.set B4_Tacc ,0x7
.set B4_Tcoh ,0x3
.set B4_Tah ,0x3
.set B4_Tacp ,0x3
.set B4_PMC ,0x0
.set B5_Tacs ,0x3
.set B5_Tcos ,0x3
.set B5_Tacc ,0x7
.set B5_Tcoh ,0x3
.set B5_Tah ,0x3
.set B5_Tacp ,0x3
.set B5_PMC ,0x0
.set B6_MT ,0x3
/*.set B6_Trcd ,0x0 */
.set B6_Trcd ,0x1
.set B6_SCAN ,0x1
.set B7_MT ,0x3
/*.set B7_Trcd ,0x0 */
.set B7_Trcd ,0x1
.set B7_SCAN ,0x1
.set REFEN ,0x1
.set TREFMD ,0x0
.set Trp ,0x0
.set Trc ,0x3
.set Tchr ,0x2
.set REFCNT ,1113
/* identify all GLOBAL symbols */
.global _start
/* GNU assembler controls */
.text /* all assembler code that follows will go into .text section */
.arm /* compile for 32?bit ARM instruction set */
.align /* align section on 32?bit boundary */
_start:
/* Set memory control registers*/
ldr r0,=SMRDATA
ldr r1,=BWSCON /* BWSCON Address*/
add r2, r0, #52 /* End address of SMRDATA*/
0:
ldr r3, [r0], #4
str r3, [r1], #4
cmp r2, r0
bne 0b
ldr r0, =_stack_end /* r0 = top?of?stack */
mov sp, r0 /* set stack pointer for SYS mode */
/* copy initialized variables .data section (Copy from ROM to RAM) */
ldr R1, =_text_end
ldr R2, =_data
ldr R3, =_data_end
1: cmp R2, R3
ldrlo R0, [R1], #4
strlo R0, [R2], #4
blo 1b
/* Clear uninitialized variables .bss section (Zero init) */
mov R0, #0
ldr R1, =_bss_start
ldr R2, =_bss_end
2: cmp R1, R2
strlo R0, [R1], #4
blo 2b
/* Enter the C code */
bl main
1:
b 1b
SMRDATA:
/*
Memory configuration should be optimized for best performance
The following parameter is not optimized.
Memory access cycle parameter strategy
1) The memory settings is safe parameters even at HCLK=75Mhz.
2) SDRAM refresh period is for HCLK=75Mhz.
*/
.word (0+(B1_BWSCON<<4)+(B2_BWSCON<<8)+(B3_BWSCON<<12)+
(B4_BWSCON<<16)+(B5_BWSCON<<20)+(B6_BWSCON<<24)+(B7_BWSCON<<28))
.word ((B0_Tacs<<13)+(B0_Tcos<<11)+(B0_Tacc<<8)+(B0_Tcoh<<6)+
(B0_Tah<<4)+(B0_Tacp<<2)+(B0_PMC)) /* GCS0 */
.word ((B1_Tacs<<13)+(B1_Tcos<<11)+(B1_Tacc<<8)+(B1_Tcoh<<6)+
(B1_Tah<<4)+(B1_Tacp<<2)+(B1_PMC)) /* GCS1 */
.word ((B2_Tacs<<13)+(B2_Tcos<<11)+(B2_Tacc<<8)+(B2_Tcoh<<6)+
(B2_Tah<<4)+(B2_Tacp<<2)+(B2_PMC)) /* GCS2 */
.word ((B3_Tacs<<13)+(B3_Tcos<<11)+(B3_Tacc<<8)+(B3_Tcoh<<6)+
(B3_Tah<<4)+(B3_Tacp<<2)+(B3_PMC)) /* GCS3 */
.word ((B4_Tacs<<13)+(B4_Tcos<<11)+(B4_Tacc<<8)+(B4_Tcoh<<6)+
(B4_Tah<<4)+(B4_Tacp<<2)+(B4_PMC)) /* GCS4 */
.word ((B5_Tacs<<13)+(B5_Tcos<<11)+(B5_Tacc<<8)+(B5_Tcoh<<6)+
(B5_Tah<<4)+(B5_Tacp<<2)+(B5_PMC)) /* GCS5 */
.word ((B6_MT<<15)+(B6_Trcd<<2)+(B6_SCAN))
/* GCS6 */
.word ((B7_MT<<15)+(B7_Trcd<<2)+(B7_SCAN))
/* GCS7 */
.word ((REFEN<<23)+(TREFMD<<22)+(Trp<<20)+(Trc<<18)+(Tchr<<16)+REFCNT)
.word 0x20 /* SCLK power saving mode, BANKSIZE 128M/128M */
.word 0x30 /* MRSR6 CL=3clk */
.word 0x30 /* MRSR7 */
/* .word 0x20 /* MRSR6 CL=2clk */
/* .word 0x20 /* MRSR7 */
.end
gatest00.ld
ENTRY(_start)
MEMORY
{
flash : ORIGIN = 0, LENGTH = 256K
ram : ORIGIN = 0x40000000, LENGTH = 4K
sdram : ORIGIN = 0x30000000, LENGTH = 32*1024K
}
_stack_end = 0x30100000;
SECTIONS
{
. = 0x30000000;
.text :
{
*(.init)
*(.text)
*(.rodata)
*(.glue_7)
*(.glue_7t)
_text_end = .;
} >sdram
.data :
{
_data = .;
*(.data)
_data_end = .;
} >sdram
.bss : /* collect all uninitialized .bss sections that go into RAM */
{
_bss_start = .;
*(.bss)
} >sdram
. = ALIGN(4);
_bss_end = . ;
}
Makefile
GNUARM = c:/sdk4arm/gat/garm/bin/
NAME = gatest00
CC = $(GNUARM)arm-elf-gcc
LD = $(GNUARM)arm-elf-ld -v
AR = $(GNUARM)arm-elf-ar
AS = $(GNUARM)arm-elf-as
CP = $(GNUARM)arm-elf-objcopy
OD = $(GNUARM)arm-elf-objdump
CFLAGS = -I . -I c:/sdk4arm/gat/garm/arm-elf/
include -c -fno-common -O0 -g
AFLAGS = -ahls -mapcs-32
LFLAGS = -Map $(NAME).map -T$(NAME).ld
CPFLAGS = --output-target=binary
ODFLAGS = -x --syms -D
all: $(NAME).bin
clean:
-rm *.lst *.o *.out *.bin *.map *.lst
$(NAME).bin: $(NAME).out
@ echo "...copying"
$(CP) $(CPFLAGS) $< $@
$(OD) $(ODFLAGS) $< > $(NAME).lst
$(NAME).out: crt.o serial.o $(NAME).o
@ echo "..linking"
$(LD) $(LFLAGS) -o $@ $^
%.o: %.s
@ echo ".assembling"
$(AS) $(AFLAGS) -o $@ $< > $%.lst
%.o: %.c
@ echo ".compiling"
$(CC) $(CFLAGS) -o $@ $<
▋ARM9 C Programs : gatest01
這個測試程式, ARM會透過Wishbone讀取wbios.v所連接的DIP Switch之值,並將此值做位移後,再透過Wishbone寫至wbios.v所連接的LED。
gatest01.c
#include <stdio.h>
#include <serial.h>
void delayms(unsigned int ms)
{
unsigned int i,j;
for(j=0;j<ms;j++)
for(i=0;i<3000;i++)
{ asm("nop"); }
}
int main()
{
int i,dpsw;
void (*prst)(void)=0;
serial_puts (" LED tests !!! \n");
do
{
dpsw=*(volatile unsigned int*)0x10000004;
for(i=0;i<32;i++)
{
*(volatile unsigned int*)0x10000000=((dpsw<<i)>>8);
delayms(100);
serial_puts ("*");
}
serial_puts ("\n");
} while(!serial_tstc());
serial_getc();
(*prst)(); // reset
return 0;
}
serial.c / serial.h / crt.h【 code內容和gatest00共用 】
gatest01.ld
ENTRY(_start)
MEMORY
{
flash : ORIGIN = 0, LENGTH = 256K
ram : ORIGIN = 0x40000000, LENGTH = 4K
sdram : ORIGIN = 0x30000000, LENGTH = 32*1024K
}
_stack_end = 0x30100000;
SECTIONS
{
. = 0x30000000;
.text :
{
*(.init)
*(.text)
*(.rodata)
*(.glue_7)
*(.glue_7t)
_text_end = .;
} >sdram
.data :
{
_data = .;
*(.data)
_data_end = .;
} >sdram
.bss : /* collect all uninitialized .bss sections that go into RAM */
{
_bss_start = .;
*(.bss)
} >sdram
. = ALIGN(4);
_bss_end = . ;
}
Makefile
GNUARM = c:/sdk4arm/gat/garm/bin/
NAME = gatest01
CC = $(GNUARM)arm-elf-gcc
LD = $(GNUARM)arm-elf-ld -v
AR = $(GNUARM)arm-elf-ar
AS = $(GNUARM)arm-elf-as
CP = $(GNUARM)arm-elf-objcopy
OD = $(GNUARM)arm-elf-objdump
CFLAGS = -I . -I c:/sdk4arm/gat/garm/arm-elf/
include -c -fno-common -O0 -g
AFLAGS = -ahls -mapcs-32
LFLAGS = -Map $(NAME).map -T$(NAME).ld
CPFLAGS = --output-target=binary
ODFLAGS = -x --syms -D
all: $(NAME).bin
clean:
-rm *.lst *.o *.out *.bin *.map *.lst
$(NAME).bin: $(NAME).out
@ echo "...copying"
$(CP) $(CPFLAGS) $< $@
$(OD) $(ODFLAGS) $< > $(NAME).lst
$(NAME).out: crt.o serial.o $(NAME).o
@ echo "..linking"
$(LD) $(LFLAGS) -o $@ $^
%.o: %.s
@ echo ".assembling"
$(AS) $(AFLAGS) -o $@ $< > $%.lst
%.o: %.c
@ echo ".compiling"
$(CC) $(CFLAGS) -o $@ $<
▋Setup & Verification
