表面上使用verilog实现POP和PUSH十分简单,实际上这里面还是有点学问的。如果是简单的堆栈实现可以这样做:
这里我就不把整个模块写出来,用for循环复位之类的我也没有写出来,主要是感受栈在verilog的实现,忽略那些细节。其实以下的做法是有问题的,因为在时序电路中,一般都是用非阻塞的,不然的话时序会很混乱的。
input wire pop; //输入出栈有效信号
input wire push; //输入入栈有效信号
input wire [31:0]push_data; //要入栈的数据
output reg [31:0]pop_data; //要输出的出栈数据
reg [31:0]stack[255:0]; //用寄存器文件实现了堆栈
reg [7:0]sp; //用来记录栈的位置
reg overflow; //这个是数据溢出报错的,为1的时候就算报错
reg no_data; //这个是没有数据在栈中的时候却想取数据
always@(posedge clk) begin
if(pop&&!push) begin
if(!sp) begin
no_data = 0;
pop_data =stack[sp];
sp = sp - 1;
end
else begin
no_data =1;//到了0的位置,不能再往下
end
end
else
if(push&&!pop) begin
if(sp<255) begin
overflow = 0;
stack[sp] = push_data;
sp = sp + 1;
end
else begin
overflow =1;//栈的位置已经到了255,不能在堆栈
end
end
else;
end
底下的是我实现ARM contex m0处理器的时候对于POP和PUSH的处理,因为ARM的是有一个reglist,所以这里对于POP和PUSH没有那么简单,使用了一个count作为POP和PUSH顺序的值。以下的做法有点问题,得不到正确答案,应该改成时序逻辑的非阻塞。那么sp就要根据一些条件给出赋值了。稍微修改即可。
if(wb_is_PUSH)
begin
if(pop_push[0]&&count==0)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[0];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[1]&&count==1)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[1];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[2]&&count==2)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[2];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[3]&&count==3)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[3];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[4]&&count==4)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[4];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[5]&&count==5)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[5];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[6]&&count==6)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[6];
overflow = 0;
end
else
overflow <= 1;
end
else
if(pop_push[7]&&count==7)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = gr[7];
overflow = 0;
end
else
overflow = 1;
end
else
if(pop_push[8]&&count==8)
begin
if(sp < 255)
begin
sp = sp +1;
stack[sp] = {16'b0,pop_push[24:9]};
overflow = 0;
end
else
overflow = 1;
end
else
overflow = 0;
end
else
if (wb_is_POP)
begin
if(pop_push[0]&&count==0)
begin
gr[0] = stack[sp[2:0]];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[1]&&count==1)
begin
gr[1] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[2]&&count==2)
begin
gr[2] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[3]&&count==3)
begin
gr[3] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[4]&&count==4)
begin
gr[4] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[5]&&count==5)
begin
gr[5] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[6]&&count==6)
begin
gr[6] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[7]&&count==7)
begin
gr[7] = stack[sp];
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else
if(pop_push[8]&&count==8)
begin
if(sp == 0)
begin
below = 1;
sp = 0;
end
else
begin
below = 0;
sp = sp -1;
end
end
else;
end
else;
end
下面是技术控制器的verilog实现:
always@(posedge clock) begin
if(!reset)
count <= 0;
else
if(count == 8)
count <= 0;
else
if(wb_is_POP || wb_is_PUSH)
count <= count + 1;
else;
end
最后修改如下,已经仿真通过:
//****************************************************************************************************************************************************
reg [3:0]count;
integer i;//进行初始化,将整块栈进行一个初始化
reg overflow;//用来表示栈已经满了,无法再加入东西,无法进行PUSH操作的时候会为一
reg below; //这个是用来当栈的指针已经指向栈底也就是sp=0的时候再进行POP操作那么就会报错,此时below为1.
//_____________________________________________________________________WB 写回_________________________________________________________________________
always@(posedge clock) //在这里把写回寄存器的序号在这一级得到而不是在取操作数的时候得到,是为了平均每一级的时间,加快运行速度。不过后来考虑到在去操作数的时候
//各个操作数是并行去操作数.在权衡之下,选择在取指的时候得出目的寄存器的序列号。这样节约了寄存器,又不会降低速度。
//为此得多付出几个寄存器。而且传递整条指令也是为了之后如果架构有改动的话,也便于从指令中得到消息。在判断该指令是什么指令的时候没有直接用指令而是传递寄存器的方式,这是减少逻辑判断。
if(!reset)
begin
gr[7] <= 32'b0;
gr[6] <= 32'b0;
gr[5] <= 32'b0;
gr[4] <= 32'b0;
gr[3] <= 32'b0;
gr[2] <= 32'b0;
gr[1] <= 32'b0;
gr[0] <= 32'b0;
for(i = 0;i<63;i=i+1)
stack[i] <= 0;
overflow <= 0;
below <= 0;
sp <= 0;
//count <= 0;
end
else if (state == `exec)
begin
if (wb_is_AND ||wb_is_EOR ||wb_is_LSL0 ||wb_is_LSR0 ||wb_is_ASR0 ||wb_is_ADC ||wb_is_SBC ||wb_is_ROR ||wb_is_NEG ||
wb_is_ORR ||wb_is_MUL ||wb_is_BIC ||wb_is_MVN ||wb_is_ADD0 ||wb_is_ADD1 ||wb_is_SUB0 ||wb_is_LDR0 ||wb_is_LDR1 ||
wb_is_LDR2 ||wb_is_LDR3 ||wb_is_LDRB0||wb_is_LDRB1||wb_is_LDRH0||wb_is_LDRH1||wb_is_LDRSB||wb_is_LDRSH||wb_is_ADD2 ||
wb_is_ADD3 ||wb_is_ADD4 ||wb_is_ADD5 ||wb_is_SUB1 ||wb_is_SUB2 ||wb_is_SUB3 ||wb_is_MOV0 ||wb_is_MOV1 ||wb_is_LSL1 ||
wb_is_LSR1 ||wb_is_ASR1)
gr[wb_rd] <= reg_C1;
else
if(wb_is_PUSH)
begin
//if(count == 8)
// count = 0;
//else
// count = count + 1;
if((pop_push[0]==1)&&(count==0)) //count = count + 1
begin
if(sp < 63) begin
sp <= sp +1;
stack[sp] <= gr[0];
overflow <= 0;
end
else
overflow <= 1;
end
else
if((pop_push[1])&&(count==1))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[1];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[2]&&(count==2))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[2];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[3]&&(count==3))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[3];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[4]&&(count==4))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[4];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[5]&&(count==5))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[5];
overflow <= 0;
end
else
overflow = 1;
end
else
if(pop_push[6]&&(count==6))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[6];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[7]&&(count==7))
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= gr[7];
overflow <= 0;
end
else
overflow <= 1;
end
else
if(pop_push[8]&&count==9)
begin
if(sp < 63)
begin
sp <= sp +1;
stack[sp] <= {16'b0,pop_push[24:9]};
overflow <= 0;
end
else
overflow <= 1;
end
else
begin
overflow <= 0;
sp <= sp;
end
end
else
if (wb_is_POP)
begin
if(pop_push[0]&&count==0)
begin
gr[0] <= stack[sp[2:0]];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[1]&&count==1)
begin
gr[1] = stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[2]&&count==2)
begin
gr[2] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[3]&&count==3)
begin
gr[3] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[4]&&count==4)
begin
gr[4] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[5]&&count==5)
begin
gr[5] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[6]&&count==6)
begin
gr[6] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[7]&&count==7)
begin
gr[7] <= stack[sp];
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
if(pop_push[8]&&count==8)
begin
if(sp == 0)
begin
below <= 1;
sp <= 0;
end
else
begin
below <= 0;
sp <= sp -1;
end
end
else
;
end
else;
end
else;
//***************************************************************************************************************************************************
//________________________________________________________控制器:用于POP,PUSH__________________________________________________________________________
//因为在有reglist的时候,POP这些操作有一个sp标志位置,但是因为得到的数据要进行堆栈的时候是并发进行的,那么就会很混乱,甚至得不到正确的结果,所以在这里使用一个时钟分频来计算这里我用
//了简单的实现,这个做起来就比较复杂,如果把系统时钟拿来分频做的话就比较简单
always@(posedge clock) begin
if(!reset)
count <= 0;
else
if(count == 8)
count <= 0;
else
if(wb_is_POP || wb_is_PUSH)
count <= count + 1;
else;
end
//***************************************************************************************************************************************************