项目需求
本项目旨在设计并实现一款基于`小脚丫FPGA套件STEP BaseBoard V4.0`的两位十进制数计算器,该计算器具备加、减、乘、除四种基本运算功能。具体需求如下:
- 输入模块:通过独立的按键矩阵输入两位十进制数以及运算符(加、减、乘、除)。输入过程应遵循从低位到高位的顺序,即用户先输入个位数,随后输入的十位数会自动移至更高位显示,原个位数码管则留作输入新的数字。
- 显示模块:采用2个4位8段数码管进行数据显示,数码管由74HC595芯片控制,节省io口。
- 运算逻辑:根据用户输入的运算符进行相应的加法、减法、乘法和除法运算,并确保运算结果的正确性。考虑了溢出和除0的情况。
需求分析
- 对于两位数计算的理解:输入数据在两位十进制数以内,即0~99;输出则根据实际情况显示。由于项目审核时要求计算结果为四位数时也得正常工作,故升级8位二进制转3位bcd为16位二进制转5位bcd,顺便解除了两位数的限制到四位数。
- 输出数字小于9999。
- 如果结果大于9999,或者减法结果为负数,则发生溢出,在另外设计的溢出指示灯上闪烁。按C键清空寄存器并退出溢出状态。
- 对于除法,不计算浮点结果,只计算商。除0时,按等号键不会进行计算,直到输入非0的除数。
- 综上所述,该计算器可以计算结果在0~9999内的加减乘除法。
为便于上板调试,引出了一些非必要的引脚:
- y_reg_led:以二进制显示y寄存器内低八位的数值。
- op_reg_led:用rgb led的不同颜色指示运算符寄存器的数值。
功能框图
其中箭头表示数据的流向,由控制逻辑控制。
代码说明
顶层输入输出
module top(
input clk, //时钟输入
input rst_n, //复位
input [3:0] col, //矩阵键盘列输入
output [3:0] row, //矩阵键盘行输出
output seg_rck, //74HC595的RCK管脚
output seg_sck, //74HC595的SCK管脚
output seg_din, //74HC595的SER管脚
output reg [2:0] of_led, //溢出指示led
// 下面的用于debug
output [7:0] y_reg_led, //y寄存器输出led
output [2:0] op_reg_led //运算符寄存器输出led
);
- clk, rst_n: 时钟、复位是必要的,用于数码管的扫描显示和键盘的扫描读取。
- col, row: 矩阵键盘的两组公共引脚。
- seg_rck, seg_sck, seg_din是74HC595的三个输入引脚,用于向芯片发送显示信息。
- of_led用于在计算发生溢出时输出1Hz的方波驱动led指示灯提示溢出。 由于核心板上为RGB LED,所以将另外两个引脚也引入,拉高电平,使其在不工作时熄灭。
寄存器
reg [15:0] x_reg; //x寄存器
reg [15:0] y_reg; //y寄存器
reg [7:0] dat_en; //数码管位使能
reg [15:0] x_bcd_reg; //x寄存器对应bcd码
reg [1:0] op_reg; //运算符寄存器
wire [15:0] bcd_out; //bcd转换输出
wire [15:0] key_out; //按键输出(无用)
wire [15:0] key_pulse; //按键输出脉冲
wire of_flag; //溢出
wire bl_wire; //1Hz脉冲闪烁
wire fin; //bcd转换完成标识
- x_reg, y_reg: 加法、减法、乘法、除法都是二元运算,而同一时刻显示在数码管上的只有一个数字,所以,设计了两个寄存器x、y,以便输入第二个数字时记录第一个数字。其中,x寄存器为16位(实际只需14位,因为包含溢出的最大可能结果为99*99=9801,转换为二进制数为14'b10_0110_0100_1001),y寄存器为8位。
- op_reg: 运算符号寄存器。有四种运算,所以设置2位。
- dat_en: 判断当前数字位数,控制显示模块显示数字个数。
- x_bcd_reg: 存储x寄存器中数值的bcd码。
- bcd_out: bcd转换输出。
- key_pulse: 实时按键检测。
- of_flag: 溢出标志。
- bl_wire: 1Hz脉冲源,在溢出时输出闪烁信号。
- fin: bcd转换完成标志。
组合逻辑
assign y_reg_led = ~y_reg[7:0];
assign op_reg_led = {1'b0,op_reg};
assign of_flag=(x_reg>9999);
// ... ... ... ...
always@(*) begin
if(x_reg>=1000) //大于1000时显示4个数字
dat_en<=8'b00001111;
else if(x_reg>=100) //大于100时显示3个数字
dat_en<=8'b00000111;
else if(x_reg >=10) //大于10时显示2个数字
dat_en<=8'b00000011;
else //否则只显示1个数字
dat_en<=8'b00000001;
if(of_flag) //溢出mux
of_led[0]<=bl_wire;
else
of_led[0]<=1;
end
- 第一行:debug使用,将y寄存器内容取反输出,因为FPGA控制LED灯的负极电平。
- 第二行:debug使用,将运算符指示灯的一个无用引脚拉低,稳定颜色。
- 第三行:溢出检测。当出现溢出时,x寄存器中的计算结果的高位会存在1,所以将x寄存器的高八位连接一个多输入或门,溢出时产生信号。
- 行为建模第一部分: 判断x寄存器中数字长度,控制显示模块的数字显示位数。
- 行为建模第二部分: 一个二选一选择器。溢出时将1Hz脉冲源输出到指示灯上。
BIN转BCD
module bin2bcd16
(
input CLK,
input RST,
input en,
input [15:0] bin,
output [3:0] bcd0,
output [3:0] bcd1,
output [3:0] bcd2,
output [3:0] bcd3,
output [3:0] bcd4,
output busy,
output fin
);
reg [15:0] bin_r;
reg [3:0] bitcount;
reg [3:0] bcd[0:4];
wire [3:0] bcdp[0:4];
assign bcd0 = bcd[0];
assign bcd1 = bcd[1];
assign bcd2 = bcd[2];
assign bcd3 = bcd[3];
assign bcd4 = bcd[4];
localparam s_idle = 2'b00;
localparam s_busy = 2'b01;
localparam s_fin = 2'b10;
reg [1:0] state;
assign busy = state != s_idle;
assign fin = state == s_fin;
always @(posedge CLK or negedge RST)
if (!RST) begin
state <= s_idle;
end else begin
case (state)
s_idle:
if (en)
state <= s_busy;
s_busy:
if (bitcount == 4'd15)
state <= s_fin;
s_fin:
state <= s_idle;
default: ;
endcase
end
always @(posedge CLK) begin
case (state)
s_idle:
if (en)
bin_r <= bin;
s_busy:
bin_r <= {bin_r[14:0], 1'b0};
default: ;
endcase
end
always @(posedge CLK or negedge RST)
if (!RST) begin
bitcount <= 4'd0;
end else begin
case (state)
s_busy:
bitcount <= bitcount + 4'd1;
default:
bitcount <= 4'd0;
endcase
end
generate
genvar g;
for (g=0; g<=4; g=g+1) begin : GEN_BCD
wire [3:0] s;
wire [3:0] prev;
assign bcdp[g] = (bcd[g] >= 4'd5) ? bcd[g] + 4'd3 : bcd[g];
if (g != 0) begin
assign prev = bcdp[g-1];
end else begin // if (g != 0)
assign prev = {bin_r[15], 3'b0};
end
assign s
= ((bcdp[g] << 1) | (prev >> 3));
always @(posedge CLK or negedge RST)
if (!RST) begin
bcd[g] <= 4'd0;
end else begin
case (state)
s_idle:
bcd[g] <= 4'd0;
s_busy:
bcd[g] <= s;
default: ;
endcase
end
end
endgenerate
endmodule
利用加3移位实现。四位二进制大于15才进位,而8421BCD码是大于9就进位,若四位二进制大于9时进位,这样得到的就是15的BCD码,因此将大于9的四位二进制数加6就能得到其BCD码。对于大于四位的二进制数,通过左移,逢9加6进位,即可转换任意位的二进制数,比如说,对于5位二进制数,由高4位二进制数左移一位得到,那么将前4位得到的BCD码也左移一位,并重新判断低四位是否大于9,若大于9,则加6进位,即可得到5位二进制数对应的BCD码。
这种实现方法易于理解,代码容易编写,但综合后电路层级复杂,延时较大,但做8位二进制以内数据转换影响不大。
实际上最初本来想直接利用所有数码管制作8位数的计算器,但按此方法综合转换模块后,再加上后续乘除法查找表的资源占用,使用资源已经超过了该芯片,因此只能缩减了配置。
溢出闪烁
module blink(
input clk,
input rst_n,
output reg blink
);
reg [23:0] counter;
always@(posedge clk)begin
if(!rst_n)begin
counter<=0;
blink <= 0;
end
else begin
counter<=counter+1;
if(counter == 12000000) begin
counter <= 0;
blink <= !blink;
end
end
end
endmodule
非常简单的利用计时器制作的闪烁功能。
模块例化
bin2bcd bb(x_reg,x_bcd_reg);
blink bl(clk,rst_n,bl_wire);
segment_scan ss(
.clk(clk),
.rst_n(rst_n),
.dat_1(4'b0),
.dat_2(4'b0),
.dat_3(4'b0),
.dat_4(4'b0),
.dat_5(4'b0),
.dat_6(x_bcd_reg[11:8]),
.dat_7(x_bcd_reg[7:4]),
.dat_8(x_bcd_reg[3:0]),
.dat_en(dat_en),
.dot_en(8'd0),
.seg_rck(seg_rck),
.seg_sck(seg_sck),
.seg_din(seg_din)
);
array_keyboard ak(
.clk(clk),
.rst_n(rst_n),
.col(col),
.row(row),
.key_out(key_out),
.key_pulse(key_pulse)
);
分别为bin转bcd码、1Hz脉冲源、扫描显示、矩阵键盘的例化。
时序逻辑
always@(posedge clk) begin
if(!rst_n) begin //按下复位重置所有状态
x_reg<=0;
y_reg<=0;
op_reg<=0;
of_led[2:1]<=2'b11;//拉高共阳指示灯的蓝色和绿色引脚,使其在发生溢出时,闪烁纯正的红色
end else begin
case(key_pulse)
16'h0001: begin
if(x_reg<10)begin
x_reg<=x_reg*10+7;
end
end
16'h0002: begin
if(x_reg<10)begin
x_reg<=x_reg*10+8;
end
end
16'h0004: begin
if(x_reg<10)begin
x_reg<=x_reg*10+9;
end
end
16'h0008: begin
y_reg<=x_reg;x_reg<=0;op_reg<=2'd3;
end
16'h0010: begin
if(x_reg<10)begin
x_reg<=x_reg*10+4;
end
end
16'h0020: begin
if(x_reg<10)begin
x_reg<=x_reg*10+5;
end
end
16'h0040: begin
if(x_reg<10)begin
x_reg<=x_reg*10+6;
end
end
16'h0080: begin
y_reg<=x_reg;x_reg<=0;op_reg<=2'd2;
end
16'h0100: begin
if(x_reg<10)begin
x_reg<=x_reg*10+1;
end
end
16'h0200:begin
if(x_reg<10)begin
x_reg<=x_reg*10+2;
end
end
16'h0400:begin
if(x_reg<10)begin
x_reg<=x_reg*10+3;
end
end
16'h0800: begin
y_reg<=x_reg;x_reg<=0;op_reg<=2'd1;
end
16'h1000: begin
if(x_reg<10)begin
x_reg<=x_reg*10;
end
end
16'h2000: x_reg <= 0;
16'h4000: begin
case(op_reg)
2'd0:x_reg <= y_reg+x_reg;
2'd1:x_reg <= y_reg-x_reg;
2'd2:x_reg <= y_reg*x_reg;
2'd3:begin //除数为0时不操作
if(x_reg!=0)
x_reg <= y_reg/x_reg;
end
endcase
end
16'h8000: begin
y_reg<=x_reg;x_reg<=0;op_reg<=2'd0;
end
endcase
end
end
复位、按键操作部分。
- 用户按下数字按键时:先对x寄存器内数值进行判断,如果为单位数,则允许用户继续输入;如果多于一位则不做处理。输入时,对应不同的数字按键分支,将x寄存器中的数值乘10后加上新输入的数字。
- 当用户输入完第一个操作数后,按下运算符号按键,将输入的运算符号记录到op寄存器中,并将x寄存器中的数值转移到y寄存器中。
- 同上述过程,输入完第二个操作数,这时需要按下等号按键。按下等号按键后,若为加、减、乘,则进行运算后把结果送入x寄存器;若为除法,则判断除数是否为0,若为0,则跳过不做任何处理,直到用户输入非零除数。
- 任何时候用户按下清零按键,都会令x寄存器中数值为0(包括用于检测溢出的位)。
显示、输入部分
这部分代码复用了stepfpga的例程,不多做赘述。
矩阵键盘
module array_keyboard #
(
parameter CNT_200HZ = 60000
)
(
input clk,
input rst_n,
input [3:0] col,
output reg [3:0] row,
output reg [15:0]key_out,
output [15:0]key_pulse
);
localparam STATE0 = 2'b00;
localparam STATE1 = 2'b01;
localparam STATE2 = 2'b10;
localparam STATE3 = 2'b11;
reg [15:0] cnt;
reg clk_200hz;
always@(posedge clk or negedge rst_n) begin //复位时计数器cnt清零,clk_200hz信号起始电平为低电平
if(!rst_n) begin
cnt <= 16'd0;
clk_200hz <= 1'b0;
end else begin
if(cnt >= ((CNT_200HZ>>1) - 1)) begin //数字逻辑中右移1位相当于除2
cnt <= 16'd0;
clk_200hz <= ~clk_200hz; //clk_200hz信号取反
end else begin
cnt <= cnt + 1'b1;
clk_200hz <= clk_200hz;
end
end
end
reg [1:0] c_state;
//状态机根据clk_200hz信号在4个状态间循环,每个状态对矩阵按键的行接口单行有效
always@(posedge clk_200hz or negedge rst_n) begin
if(!rst_n) begin
c_state <= STATE0;
row <= 4'b1110;
end else begin
case(c_state)
//状态c_state跳转及对应状态下矩阵按键的row输出
STATE0: begin c_state <= STATE1; row <= 4'b1101; end
STATE1: begin c_state <= STATE2; row <= 4'b1011; end
STATE2: begin c_state <= STATE3; row <= 4'b0111; end
STATE3: begin c_state <= STATE0; row <= 4'b1110; end
default:begin c_state <= STATE0; row <= 4'b1110; end
endcase
end
end
reg [15:0] key,key_r;
//因为每个状态中单行有效,通过对列接口的电平状态采样得到对应4个按键的状态,依次循环
always@(negedge clk_200hz or negedge rst_n) begin
if(!rst_n) begin
key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff;
end else begin
case(c_state)
//采集当前状态的列数据赋值给对应的寄存器位
//对键盘采样数据进行判定,连续两次采样低电平判定为按键按下
STATE0: begin key_out[ 3: 0] <= key_r[ 3: 0]|key[ 3: 0]; key_r[ 3: 0] <= key[ 3: 0]; key[ 3: 0] <= col; end
STATE1: begin key_out[ 7: 4] <= key_r[ 7: 4]|key[ 7: 4]; key_r[ 7: 4] <= key[ 7: 4]; key[ 7: 4] <= col; end
STATE2: begin key_out[11: 8] <= key_r[11: 8]|key[11: 8]; key_r[11: 8] <= key[11: 8]; key[11: 8] <= col; end
STATE3: begin key_out[15:12] <= key_r[15:12]|key[15:12]; key_r[15:12] <= key[15:12]; key[15:12] <= col; end
default:begin key_out <= 16'hffff; key_r <= 16'hffff; key <= 16'hffff; end
endcase
end
end
reg [15:0] key_out_r;
always @ ( posedge clk or negedge rst_n )
if (!rst_n) key_out_r <= 16'hffff;
else key_out_r <= key_out; //将前一刻的值延迟锁存
assign key_pulse= key_out_r & ( ~key_out); //通过前后两个时刻的值判断
endmodule
主要原理是对键盘的四行循环输入高电平,如果该行某列的按键为按下,则在输出端会接收到这个高电平,依次将16个电平状态存入一个寄存器。
而如果在一定间隔内,电平状态上升且不变,就说明该按键被稳定地按下(消抖)。
显示
module segment_scan(
input clk, //系统时钟 12MHz
input rst_n, //系统复位 低有效
input [3:0] dat_1, //SEG1 显示的数据输入
input [3:0] dat_2, //SEG2 显示的数据输入
input [3:0] dat_3, //SEG3 显示的数据输入
input [3:0] dat_4, //SEG4 显示的数据输入
input [3:0] dat_5, //SEG5 显示的数据输入
input [3:0] dat_6, //SEG6 显示的数据输入
input [3:0] dat_7, //SEG7 显示的数据输入
input [3:0] dat_8, //SEG8 显示的数据输入
input [7:0] dat_en, //数码管数据位显示使能,[MSB~LSB]=[SEG1~SEG8]
input [7:0] dot_en, //数码管小数点位显示使能,[MSB~LSB]=[SEG1~SEG8]
output reg seg_rck, //74HC595的RCK管脚
output reg seg_sck, //74HC595的SCK管脚
output reg seg_din //74HC595的SER管脚
);
localparam CNT_40KHz = 300; //分频系数
localparam IDLE = 3'd0;
localparam MAIN = 3'd1;
localparam WRITE = 3'd2;
localparam LOW = 1'b0;
localparam HIGH = 1'b1;
//创建数码管的字库,字库数据依段码顺序有关
//这里字库数据[MSB~LSB]={G,F,E,D,C,B,A}
reg[6:0] seg [15:0];
always @(negedge rst_n) begin
seg[0] = 7'h3f; // 0
seg[1] = 7'h06; // 1
seg[2] = 7'h5b; // 2
seg[3] = 7'h4f; // 3
seg[4] = 7'h66; // 4
seg[5] = 7'h6d; // 5
seg[6] = 7'h7d; // 6
seg[7] = 7'h07; // 7
seg[8] = 7'h7f; // 8
seg[9] = 7'h6f; // 9
seg[10] = 7'h77; // A
seg[11] = 7'h7c; // b
seg[12] = 7'h39; // C
seg[13] = 7'h5e; // d
seg[14] = 7'h79; // E
seg[15] = 7'h71; // F
end
//计数器对系统时钟信号进行计数
reg [9:0] cnt = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) cnt <= 1'b0;
else if(cnt>=(CNT_40KHz-1)) cnt <= 1'b0;
else cnt <= cnt + 1'b1;
end
//根据计数器计数的周期产生分频的脉冲信号
reg clk_40khz = 1'b0;
always@(posedge clk or negedge rst_n) begin
if(!rst_n) clk_40khz <= 1'b0;
else if(cnt<(CNT_40KHz>>1)) clk_40khz <= 1'b0;
else clk_40khz <= 1'b1;
end
//使用状态机完成数码管的扫描和74HC595时序的实现
reg [15:0] data;
reg [2:0] cnt_main;
reg [5:0] cnt_write;
reg [2:0] state = IDLE;
always@(posedge clk_40khz or negedge rst_n) begin
if(!rst_n) begin //复位状态下,各寄存器置初值
state <= IDLE;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end else begin
case(state)
IDLE:begin //IDLE作为第一个状态,相当于软复位
state <= MAIN;
cnt_main <= 3'd0; cnt_write <= 6'd0;
seg_din <= 1'b0; seg_sck <= LOW; seg_rck <= LOW;
end
MAIN:begin
cnt_main <= cnt_main + 1'b1;
state <= WRITE; //在配置完发给74HC595的数据同时跳转至WRITE状态,完成串行时序
case(cnt_main)
//对8位数码管逐位扫描
//data [15:8]为段选, [7:0]为位选
3'd0: data <= {{dot_en[7],seg[dat_1]},dat_en[7]?8'hfe:8'hff};
3'd1: data <= {{dot_en[6],seg[dat_2]},dat_en[6]?8'hfd:8'hff};
3'd2: data <= {{dot_en[5],seg[dat_3]},dat_en[5]?8'hfb:8'hff};
3'd3: data <= {{dot_en[4],seg[dat_4]},dat_en[4]?8'hf7:8'hff};
3'd4: data <= {{dot_en[3],seg[dat_5]},dat_en[3]?8'hef:8'hff};
3'd5: data <= {{dot_en[2],seg[dat_6]},dat_en[2]?8'hdf:8'hff};
3'd6: data <= {{dot_en[1],seg[dat_7]},dat_en[1]?8'hbf:8'hff};
3'd7: data <= {{dot_en[0],seg[dat_8]},dat_en[0]?8'h7f:8'hff};
default: data <= {8'h00,8'hff};
endcase
end
WRITE:begin
if(cnt_write >= 6'd33) cnt_write <= 1'b0;
else cnt_write <= cnt_write + 1'b1;
case(cnt_write)
//74HC595是串行转并行的芯片,3路输入可产生8路输出,而且可以级联使用
//74HC595的时序实现,参考74HC595的芯片手册
6'd0: begin seg_sck <= LOW; seg_din <= data[15]; end //SCK下降沿时SER更新数据
6'd1: begin seg_sck <= HIGH; end //SCK上升沿时SER数据稳定
6'd2: begin seg_sck <= LOW; seg_din <= data[14]; end
6'd3: begin seg_sck <= HIGH; end
6'd4: begin seg_sck <= LOW; seg_din <= data[13]; end
6'd5: begin seg_sck <= HIGH; end
6'd6: begin seg_sck <= LOW; seg_din <= data[12]; end
6'd7: begin seg_sck <= HIGH; end
6'd8: begin seg_sck <= LOW; seg_din <= data[11]; end
6'd9: begin seg_sck <= HIGH; end
6'd10: begin seg_sck <= LOW; seg_din <= data[10]; end
6'd11: begin seg_sck <= HIGH; end
6'd12: begin seg_sck <= LOW; seg_din <= data[9]; end
6'd13: begin seg_sck <= HIGH; end
6'd14: begin seg_sck <= LOW; seg_din <= data[8]; end
6'd15: begin seg_sck <= HIGH; end
6'd16: begin seg_sck <= LOW; seg_din <= data[7]; end
6'd17: begin seg_sck <= HIGH; end
6'd18: begin seg_sck <= LOW; seg_din <= data[6]; end
6'd19: begin seg_sck <= HIGH; end
6'd20: begin seg_sck <= LOW; seg_din <= data[5]; end
6'd21: begin seg_sck <= HIGH; end
6'd22: begin seg_sck <= LOW; seg_din <= data[4]; end
6'd23: begin seg_sck <= HIGH; end
6'd24: begin seg_sck <= LOW; seg_din <= data[3]; end
6'd25: begin seg_sck <= HIGH; end
6'd26: begin seg_sck <= LOW; seg_din <= data[2]; end
6'd27: begin seg_sck <= HIGH; end
6'd28: begin seg_sck <= LOW; seg_din <= data[1]; end
6'd29: begin seg_sck <= HIGH; end
6'd30: begin seg_sck <= LOW; seg_din <= data[0]; end
6'd31: begin seg_sck <= HIGH; end
6'd32: begin seg_rck <= HIGH; end //当16位数据传送完成后RCK拉高,输出生效
6'd33: begin seg_rck <= LOW; state <= MAIN; end
default: ;
endcase
end
default: state <= IDLE;
endcase
end
end
endmodule
按照74HC595的时序进行扫描输入,每次sck上升沿,都会将din的数据存入移位寄存器。最后给rck下降沿刷新数据。
开发板上595芯片前8位输出为位选,后8位为段选,依次位选输出数字后切换下一位继续显示。
仿真波形图
使用WebIDE模拟。
显示模块
键盘模块
1Hz 脉冲
二进制转BCD
FPGA资源利用说明
Design Summary:
Number of registers: 238 out of 4635 (5%)
PFU registers: 238 out of 4320 (6%)
PIO registers: 0 out of 315 (0%)
Number of SLICEs: 668 out of 2160 (31%)
SLICEs as Logic/ROM: 668 out of 2160 (31%)
SLICEs as RAM: 0 out of 1620 (0%)
SLICEs as Carry: 433 out of 2160 (20%)
Number of LUT4s: 1324 out of 4320 (31%)
Number used as logic LUTs: 458
Number used as distributed RAM: 0
Number used as ripple logic: 866
Number used as shift registers: 0
Number of PIO sites used: 27 + 4(JTAG) out of 105 (30%)
Number of block RAMs: 0 out of 10 (0%)
Number of GSRs: 1 out of 1 (100%)
EFB used : No
JTAG used : No
Readback used : No
Oscillator used : No
Startup used : No
POR : On
Bandgap : On
Number of Power Controller: 0 out of 1 (0%)
Number of Dynamic Bank Controller (BCINRD): 0 out of 6 (0%)
Number of Dynamic Bank Controller (BCLVDSO): 0 out of 1 (0%)
Number of DCCA: 0 out of 8 (0%)
Number of DCMA: 0 out of 2 (0%)
Number of PLLs: 0 out of 2 (0%)
Number of DQSDLLs: 0 out of 2 (0%)
Number of CLKDIVC: 0 out of 4 (0%)
Number of ECLKSYNCA: 0 out of 4 (0%)
Number of ECLKBRIDGECS: 0 out of 2 (0%)
使用webide查看。
未来计划
这个平台的资源和外设极为丰富,常用外设一应俱全,未来计划在这个芯片上构建FC游戏机的理光6502CPU、RP2C02 PPU,将其模拟成一台FC游戏机,或者老式Apple II计算机。
同时,本人正在参加“一生一芯”项目,若有可能,将会在此平台实现一部分项目中的功能。
建议
以下是对于这个板卡平台的建议:
- 核心板最好还是能支持JTAG,或者引出接口
- 数码管使用74HC595,以及矩阵键盘扫描,需要一些资源。可以考虑换成专职芯片如天微(TM)公司的一系列芯片,走总线方式传数据,避免扫描;或者可以设计两个并排的核心板插入位置,一侧用于练习在FPGA上驱动物理外设,一侧用于通过芯片连接外设
- 对于存储方面的外设比较少,建议添加SD卡槽
- FPGA内置ram只有92Kb,而屏幕以8位色显示图形需要600Kb ram,无上位机情况下,内置资源只能支持显示黑白图片,建议添加一块spi psram作为显存