一、设计前需注意
二、状态机设计
状态转移图:
三、地址与控制信号逻辑
四、仿真技巧
begin
case(i1.C_STATE)
S_IDLE:Current_State="S_IDLE";
S_READ:Current_State="S_READ";
S_REN:Current_State="S_REN";
S_WWAIT:Current_State="S_WWAIT";
S_WRITE:Current_State="S_WRITE";
S_WEN:Current_State="S_WEN";
S_WRITEP:Current_State="S_WRITEP";
S_WENP:Current_State="S_WENP";
default:Current_State="error";
endcase
end
`define S0ADD 4'b0000
`define S1ADD 4'b0001
`define S2ADD 4'b0010
`define S3ADD 4'b0011
`define S4ADD 4'b0100
`define S5ADD 4'b0101
`define S6ADD 4'b0110
`define S7ADD 4'b0111
`define S8ADD 4'b1000
`define S9ADD 4'b1001
`define S10ADD 4'b1010
`define S11ADD 4'b1011
`define S12ADD 4'b1100
`define S13ADD 4'b1101
`define S14ADD 4'b1110
`define S15ADD 4'b1111
`define TRN_IDLE 2'b00
`define TRN_BUSY 2'b01
`define TRN_NONSEQ 2'b10
`define TRN_SEQ 2'b11
`define RSP_OKAY 2'b00
`define RSP_ERROR 2'b01
`define RSP_RETRY 2'b10
`define RSP_SPLIT 2'b11
module Ahb2Apb(HCLK,HRESETn,HWDATA,HADDR,HSEL,HTRANS,HWRITE,HREADY,PRDATA,
PWDATA,PADDR,PWRITE,HRDATA,HRESP,HREADYout,PENABLE,PSEL);
//APB lite(no PREADY)
//*********************************************************************
//AHB slave inputs
input HCLK,HRESETn,HWRITE,HREADY,HSEL;
input[1:0] HTRANS;
input[31:0] HADDR,HWDATA;
//APB master input
input[31:0] PRDATA;
//AHB slave outputs
output[31:0] HRDATA;
output HREADYout;
output[1:0] HRESP;
//APB master outputs
output reg[31:0] PWDATA,PADDR;
output[15:0] PSEL; //16 slot APB
output PENABLE;
output reg PWRITE;
//lite version:RESP is always “OKAY”
assign HRESP=`RSP_OKAY;
//define state
parameter S_IDLE =8’b0000_0001; //IDLE
parameter S_READ =8’b0000_0010; //READ SETUP
parameter S_REN =8’b0000_0100; //READ ENABLE
parameter S_WWAIT =8’b0000_1000; //WAITING FOR HWDATA
parameter S_WRITE =8’b0001_0000; //WRITE SETUP(no need for a pending)
parameter S_WRITEP=8’b0010_0000; //WRITE SETUP(need a pending cycle)
parameter S_WENP =8’b0100_0000; //WRITE ENABLE(insert a pedning cycle)
parameter S_WEN =8’b1000_0000; //WRITE ENBALE(no need for a pending)
//internal signals
reg HreadyReg;
reg[31:0] HaddrReg;
reg HwriteReg;
reg[15:0] PSELint,PSELMux,PSELReg;
reg[7:0] C_STATE,N_STATE;
wire[3:0] address27to24;
wire APBEn,ACRegEn;
wire PwriteNext;
wire valid;
wire HreadyNext;
wire[31:0] HaddrMux;
// Valid AHB transfers only take place when a non-sequential or sequential
// transfer is shown on HTRANS - an idle or busy transfer should be ignored.
assign valid=(HSEL1’b1)&&(HTRANS<span class="hljs-type">TRN_NONSEQ</span>||<span class="hljs-type">HTRANS</span>==
TRN_SEQ);
//if write/read process enters a enable phase or HREADY takes place,sample Address and
//Control signals
assign ACRegEn=HREADY||(C_STATES_WENP||C_STATES_WEN||C_STATES_REN);
//APB access signal (effective when APB slave will be read or written)
assign APBEn=(N_STATES_WRITE||N_STATES_WRITEP||N_STATES_READ);
//PriteNext effective when APB slave will be writen(similar with APBEn)
assign PwriteNext=(N_STATES_WRITE||N_STATES_WRITEP);
assign HREADYout=HreadyReg;
assign HRDATA=PRDATA;
assign PENABLE=(C_STATES_WENP||C_STATES_REN||C_STATE==S_WEN);
//state machine
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
C_STATE<=S_IDLE;
else
C_STATE<=N_STATE;
end
//state transfer
always@(C_STATE or valid or HwriteReg or HWRITE)
begin
N_STATE=S_IDLE;
case(C_STATE)
S_IDLE:
if(valid&~HWRITE)
N_STATE=S_READ;
else if(valid&HWRITE)
N_STATE=S_WWAIT;
else
N_STATE=S_IDLE;
S_READ:
N_STATE=S_REN;
S_REN:
if(valid&~HWRITE)
N_STATE=S_READ;
else if(valid&HWRITE)
N_STATE=S_WWAIT;
else
N_STATE=S_IDLE;
S_WWAIT:
if(~valid)
N_STATE=S_WRITE;
else
N_STATE=S_WRITEP;
S_WRITE:
if(~valid)
N_STATE=S_WEN;
else
N_STATE=S_WENP;
S_WRITEP:
N_STATE=S_WENP;
S_WENP:
if(HwriteReg&valid)
N_STATE=S_WRITEP;
else if(HwriteReg&~valid)
N_STATE=S_WRITE;
else
N_STATE=S_READ;
S_WEN:
if(valid&HWRITE)
N_STATE=S_WWAIT;
else if(valid&~HWRITE)
N_STATE=S_READ;
else
N_STATE=S_IDLE;
default:N_STATE=S_IDLE;
endcase
end
//wait states are inserted when
//(1)READ;
//(2)WRITEP;
//(3)WENP when HWRITE shows a “read” indication but HwriteReg remains a “write”
//indication;
assign HreadyNext=((N_STATES_READ)||(N_STATES_WRITEP)||((N_STATES_WENP)&&
((~HWRITE&valid)&&(HwriteReg1’b1))||(C_STATE==S_WRITE)))?1’b0:1’b1;
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
HreadyReg<=1;
else
HreadyReg<=HreadyNext;
end
//when ACRegEn effective ,sampling start
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
begin
HwriteReg<=1;
HaddrReg<=0;
end
else if(ACRegEn)
begin
HwriteReg<=HWRITE;
HaddrReg<=HADDR;
end
end
//HaddrMux combinational module will select the right address which will be
//sampled with the enable signal APBEn for PADDR output.There are two source
//from where we can get address:(1)direct AHB input;(2)address register.And
//a new read, sequential read following another read, or a read following a
//write with no pending transfer are the only transfers that are generated
//directly from the AHB inputs. All other transfers are generated from the
//pipeline registers.
assign HaddrMux=((N_STATES_READ)&&(C_STATES_WEN||C_STATES_IDLE||
C_STATES_REN))?HADDR:HaddrReg;
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
PADDR<=0;
else if(APBEn)
PADDR<=HaddrMux;
end
//Likewise,PWRITE will be drived to APB port when APBEn effective.
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
PWRITE<=1;
else if(APBEn)
PWRITE<=PwriteNext;
end
//PWDATA will be drived to APB port when PWRITE effective;
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
PWDATA<=0;
else if(PwriteNext)
PWDATA<=HWDATA;
end
//decoder
assign address27to24=HaddrMux[27:24];
always@(address27to24)
begin
PSELint=0;
case(address27to24)
<span class="hljs-type">S0ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">0</span>]=<span class="hljs-number">1</span>;
S1ADD:PSELint[1]=1;
<span class="hljs-type">S2ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">2</span>]=<span class="hljs-number">1</span>;
S3ADD:PSELint[3]=1;
<span class="hljs-type">S4ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">4</span>]=<span class="hljs-number">1</span>;
S5ADD:PSELint[5]=1;
<span class="hljs-type">S6ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">6</span>]=<span class="hljs-number">1</span>;
S7ADD:PSELint[7]=1;
<span class="hljs-type">S8ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">8</span>]=<span class="hljs-number">1</span>;
S9ADD:PSELint[9]=1;
<span class="hljs-type">S10ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">10</span>]=<span class="hljs-number">1</span>;
S11ADD:PSELint[11]=1;
<span class="hljs-type">S12ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">12</span>]=<span class="hljs-number">1</span>;
S13ADD:PSELint[13]=1;
<span class="hljs-type">S14ADD</span>:<span class="hljs-type">PSELint</span>[<span class="hljs-number">14</span>]=<span class="hljs-number">1</span>;
S15ADD:PSELint[15]=1;
default:PSELint=0;
endcase
end
always@(*)
begin
PSELMux=0;
if(APBEn)
PSELMux=PSELint;
else if(N_STATES_IDLE||N_STATES_WWAIT)
PSELMux=0;
else
PSELMux=PSELReg;
end
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
PSELReg<=0;
else
PSELReg<=PSELMux;
end
assign PSEL=PSELReg;
endmodule
//Peripherals address decoding values:
`define S0ADD 4'b0000
`define S1ADD 4'b0001
`define S2ADD 4'b0010
`define S3ADD 4'b0011
`define S4ADD 4'b0100
`define S5ADD 4'b0101
`define S6ADD 4'b0110
`define S7ADD 4'b0111
`define S8ADD 4'b1000
`define S9ADD 4'b1001
`define S10ADD 4'b1010
`define S11ADD 4'b1011
`define S12ADD 4'b1100
`define S13ADD 4'b1101
`define S14ADD 4'b1110
`define S15ADD 4'b1111
// HTRANS transfer type signal encoding:
define TRN_IDLE <span class="hljs-number">2</span><span class="hljs-symbol">'b00</span>
define TRN_BUSY 2’b01
define TRN_NONSEQ <span class="hljs-number">2</span><span class="hljs-symbol">'b10</span>
define TRN_SEQ 2’b11
// HRESP transfer response signal encoding:
define RSP_OKAY <span class="hljs-number">2</span><span class="hljs-symbol">'b00</span>
define RSP_ERROR 2’b01
define RSP_RETRY <span class="hljs-number">2</span><span class="hljs-symbol">'b10</span>
define RSP_SPLIT 2’b11
`timescale 1 ps/ 1 ps
module Ahb2Apb_tb();
reg [31:0] HADDR;
reg HCLK;
//reg HREADY;
reg HRESETn;
reg HSEL;
reg [1:0] HTRANS;
reg [31:0] HWDATA;
reg HWRITE;
reg [31:0] PRDATA;
// wires
wire [31:0] HRDATA;
wire HREADYout;
wire [1:0] HRESP;
wire [31:0] PADDR;
wire PENABLE;
wire [15:0] PSEL;
wire [31:0] PWDATA;
wire PWRITE;
//memory HTRANS HADDR HWRITE HWDATA
reg[1:0] mem_HTRANS[0:8];
reg[31:0] mem_HADDR[0:8];
reg mem_HWRITE[0:8];
reg[31:0] mem_HWDATA[0:8];
reg[(78-1):0]PSEL_show;
reg[(78-1):0]HTRANS_show;
reg[(9*8-1):0]Current_State;
reg[3:0] cnt;
parameter S_IDLE =8’b0000_0001; //IDLE
parameter S_READ =8’b0000_0010; //READ SETUP
parameter S_REN =8’b0000_0100; //READ ENABLE
parameter S_WWAIT =8’b0000_1000; //WAITING FOR HWDATA
parameter S_WRITE =8’b0001_0000; //WRITE SETUP(no need for a pending)
parameter S_WRITEP=8’b0010_0000; //WRITE SETUP(need a pending cycle)
parameter S_WENP =8’b0100_0000; //WRITE ENABLE(insert a pedning cycle)
parameter S_WEN =8’b1000_0000; //WRITE ENBALE(no need for a pending)
always@(PSEL)
begin
case(PSEL)
16’h0001:PSEL_show=“SEL_0”;
16’h0002:PSEL_show=“SEL_1”;
16’h0004:PSEL_show=“SEL_2”;
16’h0008:PSEL_show=“SEL_3”;
16’h0010:PSEL_show=“SEL_4”;
16’h0020:PSEL_show=“SEL_5”;
16’h0040:PSEL_show=“SEL_6”;
16’h0080:PSEL_show=“SEL_7”;
16’h0100:PSEL_show=“SEL_8”;
16’h0200:PSEL_show=“SEL_9”;
16’h0400:PSEL_show=“SEL_10”;
16’h0800:PSEL_show=“SEL_11”;
16’h1000:PSEL_show=“SEL_12”;
16’h2000:PSEL_show=“SEL_13”;
16’h4000:PSEL_show=“SEL_14”;
16’h8000:PSEL_show=“SEL_15”;
default:PSEL_show=“NONE”;
endcase
end
always@(i1.C_STATE)
begin
case(i1.C_STATE)
S_IDLE:Current_State=“S_IDLE”;
S_READ:Current_State=“S_READ”;
S_REN:Current_State=“S_REN”;
S_WWAIT:Current_State=“S_WWAIT”;
S_WRITE:Current_State=“S_WRITE”;
S_WEN:Current_State=“S_WEN”;
S_WRITEP:Current_State=“S_WRITEP”;
S_WENP:Current_State=“S_WENP”;
default:Current_State=“error”;
endcase
end
always@(HTRANS)
begin
case(HTRANS)
TRN_BUSY:HTRANS_show=<span class="hljs-string">"BUSY"</span>;
TRN_IDLE:HTRANS_show=“IDLE”;
TRN_NONSEQ:HTRANS_show=<span class="hljs-string">"NONSEQ"</span>;
TRN_SEQ:HTRANS_show=“SEQ”;
endcase
end
initial
begin
mem_HADDR[0]={<!-- -->{4’b0},{S0ADD},{<span class="hljs-number">24</span><span class="hljs-symbol">'b0</span>}}; mem_HADDR[<span class="hljs-number">1</span>]={<!-- -->{<span class="hljs-number">4</span><span class="hljs-symbol">'b0</span>},{
S1ADD},{24’b0}};
mem_HADDR[2]={<!-- -->{4’b0},{S2ADD},{<span class="hljs-number">24</span><span class="hljs-symbol">'b0</span>}}; mem_HADDR[<span class="hljs-number">3</span>]={<!-- -->{<span class="hljs-number">4</span><span class="hljs-symbol">'b0</span>},{
S3ADD},{24’b0}};
mem_HADDR[4]={<!-- -->{4’b0},{S4ADD},{<span class="hljs-number">24</span><span class="hljs-symbol">'b0</span>}}; mem_HADDR[<span class="hljs-number">5</span>]={<!-- -->{<span class="hljs-number">4</span><span class="hljs-symbol">'b0</span>},{
S5ADD},{24’b0}};
mem_HADDR[6]={<!-- -->{4’b0},{S6ADD},{<span class="hljs-number">24</span><span class="hljs-symbol">'b0</span>}}; mem_HADDR[<span class="hljs-number">7</span>]={<!-- -->{<span class="hljs-number">4</span><span class="hljs-symbol">'b0</span>},{
S7ADD},{24’b0}};
mem_HADDR[8]={<!-- -->{4’b0},{S8ADD},{<span class="hljs-number">24</span><span class="hljs-symbol">'b0</span>}}; mem_HTRANS[<span class="hljs-number">0</span>]=
TRN_NONSEQ;
mem_HTRANS[1]=TRN_SEQ; mem_HTRANS[<span class="hljs-number">2</span>]=
TRN_SEQ;
mem_HTRANS[3]=TRN_NONSEQ; mem_HTRANS[<span class="hljs-number">4</span>]=
TRN_SEQ;
mem_HTRANS[5]=TRN_NONSEQ; mem_HTRANS[<span class="hljs-number">6</span>]=
TRN_IDLE;
mem_HTRANS[7]=TRN_NONSEQ; mem_HTRANS[<span class="hljs-number">8</span>]=
TRN_IDLE;
mem_HWRITE[0]=1’b1;
mem_HWRITE[1]=1’b1;
mem_HWRITE[2]=1’b1;
mem_HWRITE[3]=1’b0;
mem_HWRITE[4]=1’b0;
mem_HWRITE[5]=1’b1;
mem_HWRITE[6]=1’b1;
mem_HWRITE[7]=1’b0;
mem_HWRITE[8]=1’b1;
mem_HWDATA[0]=32’bx;
mem_HWDATA[1]=“WD0”;
mem_HWDATA[2]=“WD1”;
mem_HWDATA[3]=“WD2”;
mem_HWDATA[4]=32’bx;
mem_HWDATA[5]=32’bx;
mem_HWDATA[6]=“WD3”;
mem_HWDATA[7]=32’bx;
mem_HWDATA[8]=32’bx;
end
// assign statements (if any)
Ahb2Apb i1 (
// port map - connection between master ports and signals/registers
.HADDR(HADDR),
.HCLK(HCLK),
.HRDATA(HRDATA),
.HREADY(HREADYout),
.HREADYout(HREADYout),
.HRESETn(HRESETn),
.HRESP(HRESP),
.HSEL(HSEL),
.HTRANS(HTRANS),
.HWDATA(HWDATA),
.HWRITE(HWRITE),
.PADDR(PADDR),
.PENABLE(PENABLE),
.PRDATA(PRDATA),
.PSEL(PSEL),
.PWDATA(PWDATA),
.PWRITE(PWRITE)
);
initial
begin
HCLK=0;
HTRANS=`TRN_IDLE;
HSEL=1;
HRESETn=0;
HWRITE=1;
HWDATA=0;
PRDATA=0;
end
always
#5 HCLK=~HCLK;
always@(posedge HCLK)
begin
if(PSEL_show==“SEL_3”)
PRDATA<=“RD3”;
else if(PSEL_show==“SEL_4”)
PRDATA<=“RD4”;
else if(PSEL_show==“SEL_7”)
PRDATA<=“RD7”;
else
PRDATA<=32’bx;
end
always@(posedge HCLK or negedge HRESETn)
begin
if(!HRESETn)
cnt<=0;
else if(HREADYout)
begin
cnt<=cnt+1;
HWRITE<=mem_HWRITE[cnt];
HWDATA<=mem_HWDATA[cnt];
HADDR<=mem_HADDR[cnt];
HTRANS<=mem_HTRANS[cnt];
end
end
initial
begin
repeat(5) @(negedge HCLK)
HRESETn=1;
end
endmodule