module TANG_FPGA_Demo_Top#(
// 内部 SMMR 字节地址宽度。
parameter P_ADDR_WIDTH = 8,
// 寄存器宽度
parameter P_DATA_WIDTH = 32,
// 系统时钟频率。
parameter P_CLK_FREQ = 27_000_000
)
(
input CLOCK_XTAL_27MHz,
input RESET,
input KEY1,
input RXD,
output TXD,
input ENCORDER_A,
input ENCORDER_B,
output [2:0] LED // 110 R, 101 B, 011 G
);
////////////////////////////////////////////////////////////////////////////
// vio_uart桥接模块到 SMMR 路由模块之间的信号
////////////////////////////////////////////////////////////////////////////
wire w_reg_wr_en;
wire [8-1:0] w_reg_wr_addr;
wire [8-1:0] w_reg_rd_addr;
wire [P_DATA_WIDTH-1:0] w_reg_wr_data;
wire [P_DATA_WIDTH-1:0] w_reg_rd_data;
wire [P_ADDR_WIDTH-1:0] w_slot_wr_addr;
wire [P_ADDR_WIDTH-1:0] w_slot_rd_addr;
// 写数据会同时送到所有 slot,真正写入哪个 slot 由对应写使能决定。
wire [P_DATA_WIDTH-1:0] w_slot_wr_data;
// slot0 的写使能和读数据。
wire w_slot0_wr_en;
wire [P_DATA_WIDTH-1:0] w_slot0_rd_data;
// slot1 的写使能和读数据。
wire w_slot1_wr_en;
wire [P_DATA_WIDTH-1:0] w_slot1_rd_data;
vio_uart_smmr_bridge #(
.P_CLK_FREQ(P_CLK_FREQ),
.P_UART_BPS(115200)
) u_vio_uart_smmr_bridge (
.i_clk (CLOCK_XTAL_27MHz),
.i_rst_n (RESET),
.i_uart_rxd (RXD),
.o_uart_txd (TXD),
.o_reg_wr_en (w_reg_wr_en),
.o_reg_wr_addr (w_reg_wr_addr),
.o_reg_wr_data (w_reg_wr_data),
.o_reg_rd_addr (w_reg_rd_addr),
.i_reg_rd_data (w_reg_rd_data)
);
////////////////////////////////////////////////////////////////////////////
// SMMR slot 路由模块
//
// 该模块根据 SMMR 地址范围选择目标 slot。
// 写操作时,它给对应 slot 产生写使能。
// 读操作时,它把被选中 slot 的读数据返回给 AXI-Lite 桥接模块。
//
// 当前地址映射:
// slot0:寄存器地址 0 到 3
// slot1:寄存器地址 5 到 8
////////////////////////////////////////////////////////////////////////////
smmr_slot_router u_smmr_slot_router (
.i_clk (CLOCK_XTAL_27MHz),
.i_rst_n (RESET),
.i_reg_wr_en (w_reg_wr_en),
.i_reg_wr_addr (w_reg_wr_addr),
.i_reg_wr_data (w_reg_wr_data),
.i_reg_rd_addr (w_reg_rd_addr),
.o_reg_rd_data (w_reg_rd_data),
.o_slot_wr_addr (w_slot_wr_addr),
.o_slot_wr_data (w_slot_wr_data),
.o_slot_rd_addr (w_slot_rd_addr),
.o_slot0_wr_en (w_slot0_wr_en),
.i_slot0_rd_data(w_slot0_rd_data),
.o_slot1_wr_en (w_slot1_wr_en),
.i_slot1_rd_data(w_slot1_rd_data)
);
////////////////////////////////////////////////////////////////////////////
// slot0 外设
//
// slot0 是一个简单寄存器块。
// 它可以作为新增 SMMR 外设的模板:只需要接入写使能、地址、写数据、
// 读地址和读数据,就可以挂到系统中。
////////////////////////////////////////////////////////////////////////////
slot0 u_slot0 (
.i_clk (CLOCK_XTAL_27MHz),
.i_rst_n (RESET),
.i_reg_wr_en (w_slot0_wr_en),
.i_reg_wr_addr (w_slot_wr_addr),
.i_reg_wr_data (w_slot_wr_data),
.i_reg_rd_addr (w_slot_rd_addr),
.o_reg_rd_data (w_slot0_rd_data)
);
////////////////////////////////////////////////////////////////////////////
// slot1 编码器外设
////////////////////////////////////////////////////////////////////////////
encoder_slot u_slot1 (
.i_clk (CLOCK_XTAL_27MHz),
.i_rst_n (RESET),
.i_encoder_a(ENCORDER_A),
.i_encoder_b(ENCORDER_B),
.i_reg_wr_en (w_slot1_wr_en),
.i_reg_wr_addr (w_slot_wr_addr),
.i_reg_wr_data (w_slot_wr_data),
.i_reg_rd_addr (w_slot_rd_addr),
.o_reg_rd_data (w_slot1_rd_data)
);
endmodule
`timescale 1ns / 1ps
module encoder_slot #(
parameter P_ADDR_WIDTH = 8,
parameter P_DATA_WIDTH = 32,
parameter [P_ADDR_WIDTH-1:0] P_SLOT_BASE = 4,
parameter P_REG_COUNT = 1
)(
input wire i_clk,
input wire i_rst_n,
// SMMR
input wire i_reg_wr_en,
input wire [P_ADDR_WIDTH-1:0] i_reg_wr_addr,
input wire [P_DATA_WIDTH-1:0] i_reg_wr_data,
input wire [P_ADDR_WIDTH-1:0] i_reg_rd_addr,
output reg [P_DATA_WIDTH-1:0] o_reg_rd_data,
// Encoder
input wire i_encoder_a,
input wire i_encoder_b
);
////////////////////////////////////////////////////////////////////////////
// 内部寄存器
////////////////////////////////////////////////////////////////////////////
reg signed [15:0] r_encoder_value;
reg [1:0] r_old_code;
reg [1:0] r_encoder_sync1;
reg [1:0] r_encoder_sync2;
////////////////////////////////////////////////////////////////////////////
// 输入同步
////////////////////////////////////////////////////////////////////////////
always @(posedge i_clk or negedge i_rst_n) begin
if (!i_rst_n) begin
r_encoder_sync1 <= 2'b00;
r_encoder_sync2 <= 2'b00;
end
else begin
// A = bit0
// B = bit1
r_encoder_sync1 <= {i_encoder_b, i_encoder_a};
r_encoder_sync2 <= r_encoder_sync1;
end
end
////////////////////////////////////////////////////////////////////////////
// 编码器解码
////////////////////////////////////////////////////////////////////////////
always @(posedge i_clk or negedge i_rst_n) begin
if (!i_rst_n) begin
r_old_code <= 2'b00;
r_encoder_value <= 16'd0;
end
else if (r_encoder_sync2 != r_old_code) begin
case (r_encoder_sync2)
2'b00: begin
if (r_old_code == 2'b10)
r_encoder_value <= r_encoder_value + 16'd1;
else if (r_old_code == 2'b01)
r_encoder_value <= r_encoder_value - 16'd1;
end
2'b01: begin
if (r_old_code == 2'b00)
r_encoder_value <= r_encoder_value + 16'd1;
else if (r_old_code == 2'b11)
r_encoder_value <= r_encoder_value - 16'd1;
end
2'b11: begin
if (r_old_code == 2'b01)
r_encoder_value <= r_encoder_value + 16'd1;
else if (r_old_code == 2'b10)
r_encoder_value <= r_encoder_value - 16'd1;
end
2'b10: begin
if (r_old_code == 2'b11)
r_encoder_value <= r_encoder_value + 16'd1;
else if (r_old_code == 2'b00)
r_encoder_value <= r_encoder_value - 16'd1;
end
endcase
r_old_code <= r_encoder_sync2;
end
end
////////////////////////////////////////////////////////////////////////////
// SMMR Read
////////////////////////////////////////////////////////////////////////////
always @(*) begin
if ((i_reg_rd_addr >= P_SLOT_BASE) &&
(i_reg_rd_addr < (P_SLOT_BASE + P_REG_COUNT))) begin
// 符号扩展到32位
o_reg_rd_data = {{16{r_encoder_value[15]}}, r_encoder_value};
end
else begin
o_reg_rd_data = {P_DATA_WIDTH{1'b0}};
end
end
endmodule