nju实验七 状态机及键盘输入

news/2025/11/21 21:39:57/文章来源:https://www.cnblogs.com/mo686/p/19254582

实验七 状态机及键盘输入

简单状态机

.

├── build
├── constr
│ └── top.nxdc
├── csrc
│ └── test_our.cpp
├── dump.vcd
├── Makefile
├── MuxKeyInternal.v
├── MuxKeyWithDefault.v
├── obj_dir
├── SimReg.v
├── test_our.cpp
├── top.v
└── vsrc
└── top.v

├── constr

└── top.nxdc

top=topbutton BTNLrst_n BTNCleds (LD7, LD6, LD5, LD4, LD3, LD2, LD1, LD0)
hex0 (SEG0A, SEG0B, SEG0C, SEG0D, SEG0E, SEG0F, SEG0G, DEC0P)
hex1 (SEG1A, SEG1B, SEG1C, SEG1D, SEG1E, SEG1F, SEG1G, DEC1P)

├── csrc

└── test_our.cpp

#include<nvboard.h>
#include<Vtop.h>static TOP_NAME dut;void nvboard_bind_all_pins(TOP_NAME* top);static void single_cycle(){dut.eval();
}int main(){nvboard_bind_all_pins(&dut);nvboard_init();while(1){nvboard_update();single_cycle();}}

├── test_our.cpp

#include "verilated.h"
#include "verilated_vcd_c.h"
#include "obj_dir/Vtop.h"VerilatedContext* contextp = NULL;
VerilatedVcdC* tfp = NULL;#define MAX_SIM_TIME 60
int sim_time = 0;static Vtop* top;void step_and_dump_wave(){top->eval();contextp->timeInc(1);tfp->dump(contextp->time());
}
void sim_init(){contextp = new VerilatedContext;tfp = new VerilatedVcdC;top = new Vtop;contextp->traceEverOn(true);top->trace(tfp, 0);tfp->open("dump.vcd");
}void sim_exit(){step_and_dump_wave();tfp->close();
}int main() {sim_init();while (sim_time < MAX_SIM_TIME) {if (sim_time % 2)top->clk ^=1;if (sim_time == 48) top->reset ^= 1;if (sim_time == 2 | sim_time == 6 | sim_time == 22 | sim_time == 44) top->in ^= 1;step_and_dump_wave();sim_time ++;} sim_exit();
}

├── vsrc

└── top.v

module top (input button,           // KEY0按钮输入input rst_n,            // 复位信号(低电平有效)output [7:0] hex0,      // 低位七段数码管(直接输出编码)output [7:0] hex1,      // 高位七段数码管output [7:0] leds       // LED显示当前状态
);// 8位LFSR寄存器(初始种子为00000001)reg [7:0] lfsr = 8'b00000001;// 反馈位计算:x4 XOR x3 XOR x2 XOR x0wire feedback = lfsr[4] ^ lfsr[3] ^ lfsr[2] ^ lfsr[0];// LFSR更新逻辑always @(negedge button or posedge rst_n) beginif (rst_n) lfsr <= 8'b00000001;else beginlfsr <= {feedback, lfsr[7:1]};  // 右移并插入反馈位if (lfsr == 8'b0) lfsr <= 8'b00000001; // 防全零锁定endend// 数码管显示模块(根据您提供的编码表)seg7_decoder seg0 (.bin(lfsr[3:0]), .seg(hex0));seg7_decoder seg1 (.bin(lfsr[7:4]), .seg(hex1));// LED显示当前状态assign leds = lfsr;endmodule// 根据您提供的编码表实现的七段译码器
module seg7_decoder (input [3:0] bin,output reg [7:0] seg
);
always @(*) begincase(bin)4'h0: seg = 8'b00000011; // 04'h1: seg = 8'b10011111; // 14'h2: seg = 8'b00100101; // 24'h3: seg = 8'b00001101; // 34'h4: seg = 8'b10011001; // 44'h5: seg = 8'b01001001; // 54'h6: seg = 8'b01000001; // 64'h7: seg = 8'b00011111; // 74'h8: seg = 8'b00000001; // 84'h9: seg = 8'b00001001; // 94'hA: seg = 8'b00010001; // A(自定义)4'hB: seg = 8'b11000001; // B(自定义)4'hC: seg = 8'b01100011; // C(自定义)4'hD: seg = 8'b10000101; // D(自定义)4'hE: seg = 8'b01100001; // E(自定义)4'hF: seg = 8'b01110001; // F(自定义)default: seg = 8'b11111111; // 全灭endcase
end
endmodule

├── MuxKeyInternal.v

module MuxKeyInternal #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1, HAS_DEFAULT = 0) (output reg [DATA_LEN-1:0] out,input [KEY_LEN-1:0] key,input [DATA_LEN-1:0] default_out,input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);localparam PAIR_LEN = KEY_LEN + DATA_LEN;wire [PAIR_LEN-1:0] pair_list [NR_KEY-1:0];wire [KEY_LEN-1:0] key_list [NR_KEY-1:0];wire [DATA_LEN-1:0] data_list [NR_KEY-1:0];generatefor (genvar n = 0; n < NR_KEY; n = n + 1) beginassign pair_list[n] = lut[PAIR_LEN*(n+1)-1 : PAIR_LEN*n];assign data_list[n] = pair_list[n][DATA_LEN-1:0];assign key_list[n]  = pair_list[n][PAIR_LEN-1:DATA_LEN];endendgeneratereg [DATA_LEN-1 : 0] lut_out;reg hit;integer i;always @(*) beginlut_out = 0;hit = 0;for (i = 0; i < NR_KEY; i = i + 1) beginlut_out = lut_out | ({DATA_LEN{key == key_list[i]}} & data_list[i]);hit = hit | (key == key_list[i]);endif (!HAS_DEFAULT) out = lut_out;else out = (hit ? lut_out : default_out);endendmodule

1.模块参数说明

NR_KEY:键值对的数量
KEY_LEN:键的位宽
DATA_LEN:数据的位宽
HAS_DEFAULT:是否启用默认输出(0/1)

2.端口定义

out:查找结果输出
key:查找键
default:默认输出值
lut:键值对查找表

3.核心实现分析

3.1 查找表解包
●将连续的lut输入分解为NR_KEY个键值对
●每个键值对长度为KEY_LEN + DATA_LEN
●分别存储到key_list和data_list数组
3.2 查找逻辑
●并行比较所有键值对
●使用位掩码技术实现多路选择
●hit信号标记是否找到匹配键
●根据HAS_DEFAULT决定是否使用默认值

├── MuxKeyWithDefault.v

module MuxKeyWithDefault #(NR_KEY = 2, KEY_LEN = 1, DATA_LEN = 1) (output [DATA_LEN-1:0] out,input [KEY_LEN-1:0] key,input [DATA_LEN-1:0] default_out,input [NR_KEY*(KEY_LEN + DATA_LEN)-1:0] lut
);MuxKeyInternal #(NR_KEY, KEY_LEN, DATA_LEN, 1) i0 (out, key, default_out, lut);
endmodule

├── SimReg.v

module SimReg #(parameter WIDTH = 4,          // 寄存器位宽parameter INIT_VALUE = 0      // 初始值
) (input clk,                   // 时钟信号input reset,                 // 异步复位input [WIDTH-1:0] din,       // 数据输入output reg [WIDTH-1:0] dout, // 数据输出input wen                    // 写使能
);// 寄存器存储reg [WIDTH-1:0] reg_data = INIT_VALUE;always @(posedge clk or posedge reset) beginif (reset) beginreg_data <= INIT_VALUE;  // 异步复位end else if (wen) begin      // 写使能有效时更新reg_data <= din;endend// 持续输出assign dout = reg_data;endmodule

├── top.v

module top
(input   clk, in, reset,output reg out
);parameter[3:0] S0 = 0, S1 = 1, S2 = 2, S3 = 3,S4 = 4, S5 = 5, S6 = 6, S7 = 7, S8 = 8;wire [3:0] din, dout;
wire wen;SimReg#(4,0) state(clk, reset, din, dout, wen);assign wen = 1;MuxKeyWithDefault#(9, 4, 1) outMux(.out(out), .key(dout), .default_out(0), .lut({S0, 1'b0,S1, 1'b0,S2, 1'b0,S3, ~in,S4, ~in,S5, 1'b0,S6, 1'b0,S7, in,S8, in
}));MuxKeyWithDefault#(9, 4, 4) stateMux(.out(din), .key(dout), .default_out(S0), .lut({S0, in ? S5 : S1,S1, in ? S5 : S2,S2, in ? S5 : S3,S3, in ? S5 : S4,S4, in ? S5 : S4,S5, in ? S6 : S1,S6, in ? S7 : S1,S7, in ? S8 : S1,S8, in ? S8 : S1
}));endmodule

波形仿真

(1)编译
verilator -Wall --trace -cc top.v --exe main.cpp
(2)生成可执行文件make -C obj_dir -f Vtop.mk Vtop
(3)生成波形
./obj_dir/Vtop
(4)查看波形
gtkwave dump.vcd

摩尔型

image

米里型

image

特性 摩尔型(Moore) 米里型(Mealy)
输出决定因素 仅取决于当前状态 取决于当前状态和输入
输出时序 输出在状态变化后一个时钟周期才改变 输入变化后输出可能立即改变
状态图表示 输出写在状态圈内 输出写在转移箭头上
实现复杂度 通常需要更多状态 通常可以用较少状态实现相同功能

PS/2键盘控制器的设计

.

├── build
├── constr
│ └── top.nxdc
├── csrc
│ └── test_our.cpp
├── dump.vcd
├── Makefile
├── key_decoder.v
├── ps2_keyboard.v
├── bcd7seg.v
├── obj_dir
├── test_our.cpp
├── top.v
└── vsrc
└── top.v

├── constr

└── top.nxdc

top=topps2_clk PS2_CLK
ps2_data PS2_DATseg0 (DEC0P, SEG0G, SEG0F, SEG0E, SEG0D, SEG0C, SEG0B, SEG0A)
seg1 (DEC1P, SEG1G, SEG1F, SEG1E, SEG1D, SEG1C, SEG1B, SEG1A)
seg2 (DEC2P, SEG2G, SEG2F, SEG2E, SEG2D, SEG2C, SEG2B, SEG2A)
seg3 (DEC3P, SEG3G, SEG3F, SEG3E, SEG3D, SEG3C, SEG3B, SEG3A)
seg4 (DEC6P, SEG6G, SEG6F, SEG6E, SEG6D, SEG6C, SEG6B, SEG6A)
seg5 (DEC7P, SEG7G, SEG7F, SEG7E, SEG7D, SEG7C, SEG7B, SEG7A)

├── csrc

└── test_our.cpp

#include <nvboard.h>
#include <Vtop.h>static TOP_NAME dut;void nvboard_bind_all_pins(Vtop* top);static void single_cycle() {dut.clk = 0; dut.eval();dut.clk = 1; dut.eval();
}static void reset(int n) {dut.rst = 1;while (n-- > 0) single_cycle();dut.rst = 0;
}int main() {nvboard_bind_all_pins(&dut);nvboard_init();reset(10);while(1) {nvboard_update();single_cycle();}
}

├── test_our.cpp

#include "verilated.h"
#include "verilated_vcd_c.h"
#include "Vtop.h"vluint64_t sim_time = 0;
const vluint64_t MAX_SIM_TIME = 10000;  // 足够长的仿真时间Vtop *top;
VerilatedVcdC *tfp;// 精确时序参数(与Verilog测试一致)
const int CLK_HALF_PERIOD = 5;   // 系统时钟半周期=5ns (100MHz)
const int PS2_HALF_PERIOD = 30;  // PS/2时钟半周期=30ns (~16.7kHz)void eval_and_dump() {top->eval();tfp->dump(sim_time);sim_time++;
}void sim_init() {Verilated::traceEverOn(true);top = new Vtop;tfp = new VerilatedVcdC;top->trace(tfp, 99);tfp->open("ps2_waveform.vcd");
}void sim_exit() {tfp->close();top->final();delete top;delete tfp;
}// 精确模拟PS/2时钟和数据时序
void ps2_clock_edge(bool falling) {if (falling) {// PS/2时钟下降沿(数据变化)top->ps2_clk = 0;for (int i = 0; i < PS2_HALF_PERIOD/CLK_HALF_PERIOD; i++) {top->clk = !top->clk;eval_and_dump();}} else {// PS/2时钟上升沿(数据稳定)top->ps2_clk = 1;for (int i = 0; i < PS2_HALF_PERIOD/CLK_HALF_PERIOD; i++) {top->clk = !top->clk;eval_and_dump();}}
}// 精确模拟PS/2字节发送(与Verilog测试完全一致)
void ps2_send_byte(uint8_t byte) {// 计算奇校验位(与Verilog相同的算法)uint8_t parity = 0;for (int i = 0; i < 8; i++) {parity ^= (byte >> i) & 0x1;}parity = ~parity & 0x1;// 发送开始位(0)top->ps2_data = 0;ps2_clock_edge(true);  // 下降沿ps2_clock_edge(false); // 上升沿// 发送数据位(LSB first)for (int i = 0; i < 8; i++) {top->ps2_data = (byte >> i) & 0x1;ps2_clock_edge(true);ps2_clock_edge(false);}// 发送奇校验位top->ps2_data = parity;ps2_clock_edge(true);ps2_clock_edge(false);// 发送停止位(1)top->ps2_data = 1;ps2_clock_edge(true);ps2_clock_edge(false);// 总线空闲(与Verilog测试一致)for (int i = 0; i < 10; i++) {top->clk = !top->clk;eval_and_dump();}
}int main() {sim_init();// 初始化(与Verilog测试完全一致)top->clk = 0;top->reset_n = 0;top->ps2_clk = 1;top->ps2_data = 1;top->nextdata_n = 1;// 复位周期(20ns后释放)for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->reset_n = 1;for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}// 精确重现Verilog测试序列printf("=== 精确重现Verilog测试波形 ===\n");// 1. 发送'A'键按下(0x1C)printf("[1] 发送'A'键按下(0x1C)\n");ps2_send_byte(0x1C);// 读取数据(20ns后请求,再20ns后释放)for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}printf("[2] 读取数据\n");top->nextdata_n = 0;for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->nextdata_n = 1;// 2. 发送Break code(0xF0)printf("[3] 发送Break code(0xF0)\n");ps2_send_byte(0xF0);// 读取数据for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->nextdata_n = 0;for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->nextdata_n = 1;// 3. 发送'A'键释放(0x1C)printf("[4] 发送'A'键释放(0x1C)\n");ps2_send_byte(0x1C);// 读取数据for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->nextdata_n = 0;for (int i = 0; i < 4; i++) {top->clk = !top->clk;eval_and_dump();}top->nextdata_n = 1;// 4. 发送'S'键按下(0x1B)printf("[5] 发送'S'键按下(0x1B)\n");ps2_send_byte(0x1B);// 保持按下状态(发送两次)for (int i = 0; i < 20; i++) {top->clk = !top->clk;eval_and_dump();}ps2_send_byte(0x1B);for (int i = 0; i < 20; i++) {top->clk = !top->clk;eval_and_dump();}ps2_send_byte(0x1B);// 5. 发送Break code + 'S'键释放printf("[6] 发送'S'键释放(0xF0 0x1B)\n");ps2_send_byte(0xF0);ps2_send_byte(0x1B);// 完成仿真while (sim_time < MAX_SIM_TIME) {top->clk = !top->clk;eval_and_dump();}sim_exit();printf("=== 仿真完成,波形已保存到ps2_waveform.vcd ===\n");return 0;
}

├── vsrc

└── top.v

module top (input clk,input rst,input ps2_clk, ps2_data,output [7:0] seg0,output [7:0] seg1,output [7:0] seg2,output [7:0] seg3,output [7:0] seg4,output [7:0] seg5
);/* ps2_keyboard interface signals */
wire [7:0] data;
wire ready, overflow;
wire nextdata_n = 1'b0;ps2_keyboard inst(.clk(clk),.clrn(~rst),.ps2_clk(ps2_clk),.ps2_data(ps2_data),.data(data),.ready(ready),.nextdata_n(nextdata_n),.overflow(overflow)
);reg seg_en;
reg [7:0] cnt;
reg [1:0] state;
reg [7:0] curdata;
reg [7:0] ascii;key_decoder inst2(.clk(clk),.kbd_data(curdata),.ascii(ascii)
);wire [7:0] cnt_units = cnt % 10;  // 个位数
wire [7:0] cnt_tens = cnt / 10;   // 十位数bcd7seg bcd7seg0(.en(seg_en), .b(curdata[3:0]), .h(seg0));
bcd7seg bcd7seg1(.en(seg_en), .b(curdata[7:4]), .h(seg1));bcd7seg bcd7seg2(.en(seg_en), .b(ascii[3:0]), .h(seg2));
bcd7seg bcd7seg3(.en(seg_en), .b(ascii[7:4]), .h(seg3));bcd7seg bcd7seg4(.en(1), .b(cnt_units[3:0]), .h(seg4));
bcd7seg bcd7seg5(.en(1), .b(cnt_tens[3:0]), .h(seg5));always @(posedge clk) beginif (rst == 0 && ready) begin$display("keyboard: %x", data);if (state == 2'b00) beginseg_en <= 1'b1;if (cnt < 99) cnt <= cnt + 8'd1;else cnt <= 0;curdata <= data;state <= 2'b01;end else if (state == 2'b01) beginif (data == 8'hf0) beginstate <= 2'b10;seg_en <= 1'b0;endend else if (state == 2'b10) beginstate <= 2'b00;endend
endinitial beginseg_en = 1'b0;cnt = 0;state = 0;
endendmodule

├── key_decoder.v

module key_decoder (input clk,input [7:0] kbd_data,output reg [7:0] ascii
);always @(posedge clk) begincase (kbd_data)8'h1c: ascii <= 8'h61; // a8'h32: ascii <= 8'h62; // b8'h21: ascii <= 8'h63; // c8'h23: ascii <= 8'h64; // d8'h24: ascii <= 8'h65; // e8'h2b: ascii <= 8'h66; // f8'h34: ascii <= 8'h67; // g8'h33: ascii <= 8'h68; // h8'h43: ascii <= 8'h69; // i8'h3b: ascii <= 8'h6a; // j8'h42: ascii <= 8'h6b; // k8'h4b: ascii <= 8'h6c; // l8'h3a: ascii <= 8'h6d; // m8'h31: ascii <= 8'h6e; // n8'h44: ascii <= 8'h6f; // o8'h4d: ascii <= 8'h70; // p8'h15: ascii <= 8'h71; // q8'h2d: ascii <= 8'h72; // r8'h1b: ascii <= 8'h73; // s8'h2c: ascii <= 8'h74; // t8'h3c: ascii <= 8'h75; // u8'h2a: ascii <= 8'h76; // v8'h1d: ascii <= 8'h77; // w8'h22: ascii <= 8'h78; // x8'h35: ascii <= 8'h79; // y8'h1a: ascii <= 8'h7a; // z8'h45: ascii <= 8'h30; // 08'h16: ascii <= 8'h31; // 18'h1e: ascii <= 8'h32; // 28'h26: ascii <= 8'h33; // 38'h25: ascii <= 8'h34; // 48'h2e: ascii <= 8'h35; // 58'h36: ascii <= 8'h36; // 68'h3d: ascii <= 8'h37; // 78'h3e: ascii <= 8'h38; // 88'h46: ascii <= 8'h39; // 9default: ascii <= 8'h00;endcase
endendmodule

├── ps2_keyboard.v

接收键盘送来的数据
image
image
image

├── bcd7seg.v

module bcd7seg(input [3:0] b,input en,output reg [7:0] h
);always @(*) beginif (!en) beginh = 8'b11111111;end else case(b)4'h0: h = 8'b00000011; // 04'h1: h = 8'b10011111; // 14'h2: h = 8'b00100101; // 24'h3: h = 8'b00001101; // 34'h4: h = 8'b10011001; // 44'h5: h = 8'b01001001; // 54'h6: h = 8'b01000001; // 64'h7: h = 8'b00011111; // 74'h8: h = 8'b00000001; // 84'h9: h = 8'b00001001; // 94'hA: h = 8'b00010001; // A4'hB: h = 8'b11000001; // B4'hC: h = 8'b01100011; // C4'hD: h = 8'b10000101; // D4'hE: h = 8'b01100001; // E4'hF: h = 8'b01110001; // Fdefault: h = 8'b11111111; // 全灭endcaseendendmodule

├── top.v

module top(input clk,input reset_n,input ps2_clk,input ps2_data,input nextdata_n,output [7:0] ascii_out,output ready,output key_pressed,output overflow
);// 内部连接信号wire [7:0] scan_code;// PS/2键盘接收模块ps2_keyboard keyboard_receiver (.clk(clk),.clrn(reset_n),.ps2_clk(ps2_clk),.ps2_data(ps2_data),.data(scan_code),.ready(ready),.nextdata_n(nextdata_n),  // 持续读取数据.overflow(overflow));// 扫描码转ASCII解码模块key_decoder decoder (.clk(clk),.rst_n(reset_n),.scan_code(scan_code),.data_ready(ready),.ascii(ascii_out),.key_pressed(key_pressed));endmodule

波形仿真

(1)编译
verilator -Wall --trace -cc top.v --exe main.cpp
(2)生成可执行文件make -C obj_dir -f Vtop.mk Vtop
(3)生成波形
./obj_dir/Vtop
(4)查看波形
gtkwave dump.vcd

image

接入NVBoard

make
cd build
./top

效果

高级选做内容

●支持Shift,CTRL等组合键,在LED上显示组合键是否按下的状态指示
●支持Shift键与字母/数字键同时按下,相互不冲突
●支持输入大写字符,显示对应的ASCII码

always @(posedge clk) beginif (rst) beginshift_state <= 1'b0;ctrl_state <= 1'b0;state <= 2'b00;seg_en <= 1'b0;cnt <= 0;endelse if (ready) begin$display("keyboard: %x", data);case (state)2'b00: beginif (data == 8'hf0) begin// 释放前缀,进入状态01state <= 2'b01;seg_en <= 1'b0;endelse if (data == 8'h12 || data == 8'h59) begin // Shift键按下shift_state <= 1'b1;state <= 2'b10;seg_en <= 1'b0;endelse if (data == 8'h14) begin // Ctrl键按下ctrl_state <= 1'b1;state <= 2'b10;seg_en <= 1'b0;endelse begin // 普通键按下seg_en <= 1'b1;if (cnt < 99) cnt <= cnt + 8'd1;else cnt <= 0;curdata <= data;state <= 2'b10;endend2'b01: begin // 处理键释放if (data == 8'h12 || data == 8'h59) begin // Shift键释放shift_state <= 1'b0;endelse if (data == 8'h14) begin // Ctrl键释放ctrl_state <= 1'b0;endstate <= 2'b00;end2'b10: begin // 完成按键处理if (data == 8'hf0) begin// 释放前缀,进入状态01state <= 2'b01;seg_en <= 1'b0;endelse state <= 2'b00;enddefault: ;endcaseend
endinitial beginseg_en = 1'b0;cnt = 0;state = 0;shift_state = 0;ctrl_state = 0;
end
module key_decoder (input clk,input shift,        // Shift键状态input [7:0] kbd_data,output reg [7:0] ascii
);always @(posedge clk) begincase (kbd_data)// 字母键 (支持Shift)8'h1c: ascii <= shift ? 8'h41 : 8'h61; // A/a8'h32: ascii <= shift ? 8'h42 : 8'h62; // B/b8'h21: ascii <= shift ? 8'h43 : 8'h63; // C/c8'h23: ascii <= shift ? 8'h44 : 8'h64; // D/d8'h24: ascii <= shift ? 8'h45 : 8'h65; // E/e8'h2b: ascii <= shift ? 8'h46 : 8'h66; // F/f8'h34: ascii <= shift ? 8'h47 : 8'h67; // G/g8'h33: ascii <= shift ? 8'h48 : 8'h68; // H/h8'h43: ascii <= shift ? 8'h49 : 8'h69; // I/i8'h3b: ascii <= shift ? 8'h4A : 8'h6a; // J/j8'h42: ascii <= shift ? 8'h4B : 8'h6b; // K/k8'h4b: ascii <= shift ? 8'h4C : 8'h6c; // L/l8'h3a: ascii <= shift ? 8'h4D : 8'h6d; // M/m8'h31: ascii <= shift ? 8'h4E : 8'h6e; // N/n8'h44: ascii <= shift ? 8'h4F : 8'h6f; // O/o8'h4d: ascii <= shift ? 8'h50 : 8'h70; // P/p8'h15: ascii <= shift ? 8'h51 : 8'h71; // Q/q8'h2d: ascii <= shift ? 8'h52 : 8'h72; // R/r8'h1b: ascii <= shift ? 8'h53 : 8'h73; // S/s8'h2c: ascii <= shift ? 8'h54 : 8'h74; // T/t8'h3c: ascii <= shift ? 8'h55 : 8'h75; // U/u8'h2a: ascii <= shift ? 8'h56 : 8'h76; // V/v8'h1d: ascii <= shift ? 8'h57 : 8'h77; // W/w8'h22: ascii <= shift ? 8'h58 : 8'h78; // X/x8'h35: ascii <= shift ? 8'h59 : 8'h79; // Y/y8'h1a: ascii <= shift ? 8'h5A : 8'h7a; // Z/z// 数字键 (支持Shift切换符号)8'h16: ascii <= shift ? 8'h21 : 8'h31; // 1/!8'h1e: ascii <= shift ? 8'h40 : 8'h32; // 2/@8'h26: ascii <= shift ? 8'h23 : 8'h33; // 3/#8'h25: ascii <= shift ? 8'h24 : 8'h34; // 4/$8'h2e: ascii <= shift ? 8'h25 : 8'h35; // 5/%8'h36: ascii <= shift ? 8'h5E : 8'h36; // 6/^8'h3d: ascii <= shift ? 8'h26 : 8'h37; // 7/&8'h3e: ascii <= shift ? 8'h2A : 8'h38; // 8/*8'h46: ascii <= shift ? 8'h28 : 8'h39; // 9/(8'h45: ascii <= shift ? 8'h29 : 8'h30; // 0/)default: ascii <= 8'h00;endcase
endendmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/972564.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

2025-11-21 XQQ NOIP Round 1 hetao1733837的record

2025-11-21 XQQ NOIP Round 1 hetao1733837的record2025-11-21 XQQ NOIP Round 1 hetao1733837的record A.tree 提交链接:树 题面 题目描述 给定一棵 $n$ 个点的树和一个长度为 $n$ 的数组 $score[0], ..., score[n-1…

Gephi如何支持MySQL数据的复杂查询

Gephi是一个用于网络可视化的开源软件,它主要处理的是图数据结构。虽然Gephi本身并不直接支持MySQL数据库的复杂查询,但你可以通过以下步骤将MySQL中的数据导入到Gephi中,并在Gephi中进行进一步的处理和分析:数据提…

Mozilla CI日志中暴露微软x-apikey的安全事件分析

微软遥测API密钥在Mozilla持续集成公共日志中意外暴露。该密钥出现在自动化Firefox测试期间发送到微软遥测端点的HTTP POST请求中,通过mitmproxy日志捕获。尽管安全影响有限,但Mozilla已采取措施防止未来凭证泄露。报…

Gephi中MySQL数据的节点和边如何设置

在Gephi中,使用MySQL数据源时,首先需要导入数据到Gephi的工作空间。以下是设置节点(Node)和边(Edge)的一般步骤:导入MySQL数据:使用Gephi的MySQL插件或其他适当的方法连接到您的MySQL数据库。 执行SQL查询以提…

Gephi怎样优化MySQL数据的展示效果

Gephi是一个用于网络可视化的开源软件,它可以帮助用户创建网络图和数据可视化。然而,Gephi本身并不直接与MySQL数据库交互,它通常用于处理和分析已经存在于内存或文件中的数据集。如果你想要优化MySQL数据的展示效果…

Gephi对MySQL数据的导入导出有何支持

Gephi是一个用于网络可视化的开源软件,它主要处理的是图数据结构。关于Gephi对MySQL数据的导入导出支持,这通常取决于Gephi的版本以及用户是否进行了特定的配置或开发。在标准的Gephi版本中,可能并没有直接针对MySQ…

Fisrt Blog

音视频简介 这是单个代码,find() 这是一段代码 #include<stdio.h> int main() {code } 213213"213231" 这是斜体 这是加粗 ffmpeg find函数她有以下几个用法:第一个用法是 第二个用法我是十个机器人…

揭秘Java对象的内存占用量:从面试题到底层原理

你是否在面试中被问到过:“一个new Object()在JVM中占多少内存?” 这个问题看似简单,却考察了你对Java内存模型(JVM)、数据结构和性能优化的理解深度。今天,我们就来彻底搞懂它。 一、核心结论:一个Java对象的三…

nju实验六 移位寄存器及桶形移位器

本实验将学习常用的移位寄存器的设计,并实现在移位指令中需要用到的桶形移位器。实验六 移位寄存器及桶形移位器 算术移位和逻辑移位寄存器 module shift_register_8bit (input clk, // 时钟信号input r…

P6727 [COCI 2015/2016 #5] OOP

题目给出字符串按 * 断开得到前后两段 \(P,S\),即要求满足一下条件的模式串个数:具有前缀 \(P\),后缀 \(S\)。\(|P|+|S|\le siz\)。

c语言和python如何解决文本文件中“不同平台换行符不兼容”问题

在 C 语言和 Python 中解决不同平台换行符不兼容的核心思路一致:统一换行符标准(推荐使用 \n),或在读写时适配目标平台。以下是具体实现方案: 一、核心背景:不同平台的换行符差异平台 换行符 说明Unix/Linux \n …

智能制造(MOM)-详细设计 - 智慧园区

数字化智能制造成熟度框架 数字化智能工厂应用架构 数字化智能工厂技术架构 数字化智能工厂制造体系 未来数字化智能工厂愿景 价值驱动的数字化智能工厂指标 关键环节解决方案 端到端闭环的运营协同 产品BOPIMBOM数据流…

完整教程:政务系统信创改造中,金仓日志如何满足等保2.0三级审计要求

完整教程:政务系统信创改造中,金仓日志如何满足等保2.0三级审计要求2025-11-21 21:12 tlnshuju 阅读(0) 评论(0) 收藏 举报pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto…

基于 Erlang 的英文数字验证码识别系统设计与实现

一、引言 验证码(CAPTCHA)作为互联网中抵御自动化攻击的重要安全机制,被广泛用于登录验证、注册防刷、评论防机器人等场景。 传统验证码识别常用 Python 或 C++ 实现,而本文将介绍如何用 Erlang 来构建一个基础的英…

如何使用IDM嗅探视频并下载?

用 IDM 嗅探下载网页视频,优先用浏览器浮窗一键下载;浮窗不出现则补全插件/格式、手动抓直链或用站点抓取;加密/分离流需先合并,全程遵守版权与站点规则。🎬前置准备(必做)安装官方最新 IDM,激活并重启;安装…

洛谷 B4409:[GESP202509 一级] 商店折扣 ← 模拟算法

​【题目来源】https://www.luogu.com.cn/problem/B4409【题目描述】商店正在开展促销活动,给出了两种方案的折扣优惠。第一种方案是购物满 x 元减 y 元;第二种方案是直接打 n 折,也就是说价格变为原先的 n/10。这里…

java数据结构--LinkedList与链表 - 教程

java数据结构--LinkedList与链表 - 教程pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Mo…

STM32中断、NVIC、EXTI

一、如何提高程序的实时性 轮询式系统 指的是在程序运行时,首先对所有的硬件进行初始化,然后在主程序中写一个死循环,需要运行的功能按照顺序进行执行,轮询系统是一种简单可靠的方式,一般适用于在只需要按照顺序执…

深入解析:自动化文件管理:分类、重命名和备份

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

nju实验三 加法器与ALU

加法是数字系统中最常执行的运算,加法器是ALU(算术逻辑部件 Arithmetic-Logic Unit )的核心部件。 减法可以看作是被减数与取负后的减数进行加法。即用加法器同时实现加法和减法两种运算。乘法也可以利用移位相加的…