这里的设计参考了arm的ip。
1.接口信号
(1)对于ahb这一侧,相当于ahb-slave的接口信号,基本信号包含:
hclk,hrst_n,hready_in,hready_out,hwrite,hwdata,hrdata,hsel,haddr,htrans,hsize,hprot,hresp
注意这里是ahb-lite的版本,hresp只有error和okay两种情况。
(2)apb这一侧:
psel,penable,pwrite,paddr,pwdata,prdata,pready,pslverr,pstrb,pprot。
注意这里没有pclk信号,外部输入的是pclken信号当做apb的时钟,关于pclken信号的产生逻辑需要mater单独给,如下:
always@(posedge hclk or negedge hresetn)
begin
if(!hresetn)
hclk_cnt <= 4'b0;
else if(hclk_cnt == HCLK_PCLK_RATIO - 1'b1)
hclk_cnt <= 4'b0;
else
hclk_cnt <= hclk_cnt + 1'b1;
end
always@(negedge hclk or negedge hresetn)
begin
if(!presetn)
pclk_en <= 1'b0;
else if(hclk_cnt == HCLK_PCLK_RATIO - 1'b1)
pclk_en <= 1'b1;
else
pclk_en <= 1'b0;
end
也就是pclk_en是hclk分频出来的,文档中规定了这两个信号需要时同相位的。
此外系统中还存在一个apb-active信号。这个信号是用来表示这个桥是否处于工作状态的信号,这个信号存在的意义在于可以将这个信号和pclk进行gate,降低功耗。
2.内部状态机:
该设计支持通过参数化的配置来设定当前写入或者读出数据是否需要寄存,这样做的目的在于高频下解决时序上的问题。
整个内部状态机共有七个状态:
idle状态,wait1状态,setup状态,enable状态,wait2状态,error1状态,error2状态。
1.idle状态会向wait1状态和setup状态进行跳,wait1状态表示的是是否对输入数据进行寄存。
(1)如果psel信号为1+配置参数对输入数据寄存+hwrite那么进入wait1状态。
(2)idle状态往setup状态直接跳有两种情况,
第一种是写操作时,那么此时需要对输入数据寄存一拍的配置参数为0+psel+pclken;
第二种是读操作,无论配置参数是否为1,只需要满足psel+pclken;
ST_IDLE : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
2.wait1状态:
此状态下下一拍就会进入setup状态(实际代码中这里写的是:如果pclken为1的话进入setup状态,但是需要注意的是,实际上pclken的逻辑是只要他不是idle状态他就为1,个人觉得加这个逻辑有点冗余。)
ST_APB_WAIT : begin
if (PCLKEN)
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
end
3.setup下一拍进入enable,代码中同样是pclken为1的时候进入。
ST_APB_TRNF : begin
if (PCLKEN)
next_state = ST_APB_TRNF2; // Change to second cycle of APB transfer
else
next_state = ST_APB_TRNF; // Change to state-2
end
4.enable状态的跳转有四种,分别如下:
(1)当apb-slave返回的ready信号为1+pslverr为0+pclken的时候进入error状态;
(2)当apb-slave返回的ready信号为1+pslverr为0的时候表示这次传输成功,再此基础上加上pclken+配置参数配置读数据需要寄存一拍时进入wait2状态;
(3)当apb-slave返回的ready信号为1+pslverr为0+apb-selct表示紧接着又进行了一此数据的传输,因此进入wait1状态
(4)当apb-slave返回的ready信号为1+pslverr为0+!apb-selct表示紧接着没有数据的传输,因此进入idle状态
ST_APB_TRNF2 : begin
if (PREADY & PSLVERR & PCLKEN) // Error received - Generate two cycle
// Error response on AHB by
next_state = ST_APB_ERR1; // Changing to state-5 and 6
else if (PREADY & (~PSLVERR) & PCLKEN) begin // Okay received
if (reg_rdata_cfg)
// Registered version
next_state = ST_APB_ENDOK; // Generate okay response in state 4
else
// Non-registered version
next_state = {2'b00, apb_select}; // Terminate transfer
end
else
// Slave not ready
next_state = ST_APB_TRNF2; // Unchange
end
注意,在上述的条件下,如果apb-select为1的话实际上进入的是wait1状态,wait1跳到setup需要一拍,setup跳到enable需要一拍,也就是penable至少两拍之后才能再次拉高。
5.wait2状态的跳转:
(1)如果pclken+apb_select+(配置输入数据不需要寄存+写操作)或(读操作)那么均是进入setup状态
(2)如果是apb-select+写操作+配置输入数据需要寄存一拍进入wait1状态
(3)如果没有apb_selct进入idle状态。
ST_APB_ENDOK : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
6.error1
error1下一状态进入error2
ST_APB_ERR1 :
next_state = ST_APB_ERR2;
7.error2
error2状态的跳转和wait2状态的跳转相同。
ST_APB_ERR2 : begin
if (PCLKEN & apb_select & ~(reg_wdata_cfg & HWRITE))
next_state = ST_APB_TRNF; // Start APB transfer in next cycle
else if (apb_select)
next_state = ST_APB_WAIT; // Wait for start of APB transfer at PCLKEN high
else
next_state = ST_IDLE; // Remain idle
end
3.信号输出
always @(state_reg or reg_rdata_cfg or PREADY or PSLVERR or PCLKEN)
begin
case (state_reg)
ST_IDLE : HREADYOUT = 1'b1; // Idle
ST_APB_WAIT : HREADYOUT = 1'b0; // Transfer announced on AHB, but PCLKEN was low, so waiting
ST_APB_TRNF : HREADYOUT = 1'b0; // First APB transfer cycle
// Second APB transfer cycle:
// if Non-registered feedback version, and APB transfer completed without error
// Then response with ready immediately. If registered feedback version,
// wait until state_reg==ST_APB_ENDOK
ST_APB_TRNF2 : HREADYOUT = (~reg_rdata_cfg) & PREADY & (~PSLVERR) & PCLKEN;
ST_APB_ENDOK : HREADYOUT = reg_rdata_cfg; // Ending cycle for OKAY (registered response only)
ST_APB_ERR1 : HREADYOUT = 1'b0; // First cycle for Error response
ST_APB_ERR2 : HREADYOUT = 1'b1; // Second cycle for Error response
default: HREADYOUT = 1'bx; // x propagation (note :3'b111 is illegal state)
endcase
end
关于hreadyout输出的逻辑就是idle状态下为1,enable状态下,如果输出不需要寄存+hready+!error+pclken就为1,wait2状态下如果输出需要寄存为1,其他状态均为0.