在之前的Lab3中,通过一个初具规模的MCDT的验证环境,学习到:

  • 验证环境按照隔离的观念,应分为硬件DUT,软件验证环境,和处于信号媒介的接口interface。
  • 对于软件验证环境,需要经历建立阶段(build),连接阶段(connect),产生激励阶段(generate)和发送激励阶段(transfer),只有当所有的激励发送完毕并且比较完全之后,才可以结束该测试。

从Lab4开始,要验证更大的子系统,即MCDF。与MCDT相比,MCDF主要添加了寄存器控制状态显示功能,同时也添加了一个重要的数据整形功能。不同的package之间的功能是独立的,同一个package中的各个验证组件的功能也是独立的。

一、本次实验的测试功能点

测试功能点 测试内容 测试通过标准 测试类名
寄存器读写测试 所有控制寄存器的读写测试;所有状态寄存器的读写测试 读写值是否正确 mcdf_reg_write_read_test
寄存器稳定性测试 非法地址读写;对控制寄存器的保留域进行读写;对状态寄存器进行写操作 通过写入和读出,确定寄存器的值时预期值,而不是紊乱值,同时非法寄存器操作也不能影响MCDF的整体功能 mcdf_reg_illegal_access_test
数据通道开关测试 对每一个数据通道对应的控制寄存器域en配置为0,在关闭状态下测试数据写入是否通过 在数据通过关闭情况下,数据无法写入,同时ready信号应该保持为低,表示不接收数据,但又能使得数据不被丢失,因此数据只会停留在数据通道端口 mcdf_channel_disable_test
优先级测试 将不同数据通道配置为相同或者不同的优先级,在数据通道使能的情况下进行测试 如果优先级相同,那么arbiter应该采取轮询机制从各个通道接受数据,如果优先级不同,那么arbiter应该先接收高优先级通道的数据,同时最终所有的数据都应该从MCDF发送出来 mcdf_arbiter_priority_test
发包长度测试 将不同数据通道随机配置为各自的长度,在数据通道使能的情况下进行测试 从formatter发送出来的数据包长度应该同对于通道寄存器的配置值保持一一对应,同时数据也应该保持完整 mcdf_formatter_length_test
下行从端低带宽测试 将MCDF下行数据接收端设置为小存储量,低带宽的类型,由此使得在由formatter发送出数据之后,下行从端有更多的机会延迟grant信号的置位,用来模拟真实场景 在req拉高之后,grant应该在至少两个时钟周期以后拉高,以此来模拟下行从端数据余量不足的情况,当这种激励时序发生10次之后,可以停止测试 mcdf_formatter_grant_test

二、验证环境框图

三、代码实现

mcdf_pkg.sv

mcdf_pkg包实现了mcdf_checker功能,reg_agentchnl_agentfmt_agent三个组件中的monitor都会把监测到的数据交给mcdf_checkerchnl_agent监测到的数据是单个的数据,即32bit的数据,而fmt_agent监测到的数据是一个数据包,意味着chnl_mbfmt_mb里面的数据格式不一样,所以在比较之前,要将reg和channel监测到的数据通过mcdf_refmod这个参考模型来做整形转化

mcdf_reg_t结构体,用来描述寄存器数据的构成,包括长度、优先级、使能以及存储余量。

  typedef struct packed {bit[2:0] len;bit[1:0] prio;bit en;bit[7:0] avail;} mcdf_reg_t;

mcdf_refmod

  class mcdf_refmod;local virtual mcdf_intf intf;local string name;mcdf_reg_t regs[3];mailbox #(reg_trans) reg_mb;mailbox #(mon_data_t) in_mbs[3];mailbox #(fmt_trans) out_mbs[3];function new(string name="mcdf_refmod");this.name = name;foreach(this.out_mbs[i]) this.out_mbs[i] = new();endfunctiontask run();forkdo_reset();this.do_reg_update();do_packet(0);do_packet(1);do_packet(2);joinendtasktask do_reg_update();reg_trans t;forever beginthis.reg_mb.get(t);if(t.addr[7:4] == 0 && t.cmd == `WRITE) beginthis.regs[t.addr[3:2]].en = t.data[0];this.regs[t.addr[3:2]].prio = t.data[2:1];this.regs[t.addr[3:2]].len = t.data[5:3];endelse if(t.addr[7:4] == 1 && t.cmd == `READ) beginthis.regs[t.addr[3:2]].avail = t.data[7:0];endendendtasktask do_packet(int id);fmt_trans ot;mon_data_t it;bit[2:0] len;forever beginthis.in_mbs[id].peek(it);ot = new();len = this.get_field_value(id, RW_LEN);ot.length = len > 3 ? 32 : 4 << len;ot.data = new[ot.length];ot.ch_id = id;foreach(ot.data[m]) beginthis.in_mbs[id].get(it);ot.data[m] = it.data;endthis.out_mbs[id].put(ot);endendtaskfunction int get_field_value(int id, mcdf_field_t f);case(f)RW_LEN: return regs[id].len;RW_PRIO: return regs[id].prio;RW_EN: return regs[id].en;RD_AVAIL: return regs[id].avail;endcaseendfunction task do_reset();forever begin@(negedge intf.rstn); foreach(regs[i]) beginregs[i].len = 'h0;regs[i].prio = 'h3;regs[i].en = 'h1;regs[i].avail = 'h20;endendendtaskfunction void set_interface(virtual mcdf_intf intf);if(intf == null)$error("interface handle is NULL, please check if target interface has been intantiated");elsethis.intf = intf;endfunctionendclass

mcdf_checker

  class mcdf_checker;local string name;local int err_count;local int total_count;local int chnl_count[3];local virtual mcdf_intf intf;local mcdf_refmod refmod;mailbox #(mon_data_t) chnl_mbs[3];mailbox #(fmt_trans) fmt_mb;mailbox #(reg_trans) reg_mb;mailbox #(fmt_trans) exp_mbs[3];function new(string name="mcdf_checker");this.name = name;foreach(this.chnl_mbs[i]) this.chnl_mbs[i] = new();this.fmt_mb = new();this.reg_mb = new();this.refmod = new();foreach(this.refmod.in_mbs[i]) beginthis.refmod.in_mbs[i] = this.chnl_mbs[i];this.exp_mbs[i] = this.refmod.out_mbs[i];endthis.refmod.reg_mb = this.reg_mb;this.err_count = 0;this.total_count = 0;foreach(this.chnl_count[i]) this.chnl_count[i] = 0;endfunctionfunction void set_interface(virtual mcdf_intf intf);if(intf == null)$error("interface handle is NULL, please check if target interface has been intantiated");elsethis.intf = intf;this.refmod.set_interface(intf);endfunctiontask run();forkthis.do_compare();this.refmod.run();joinendtasktask do_compare();fmt_trans expt, mont;bit cmp;forever beginthis.fmt_mb.get(mont);this.exp_mbs[mont.ch_id].get(expt);cmp = mont.compare(expt);   this.total_count++;this.chnl_count[mont.ch_id]++;if(cmp == 0) beginthis.err_count++;rpt_pkg::rpt_msg("[CMPFAIL]", $sformatf("%0t %0dth times comparing but failed! MCDF monitored output packet is different with reference model output", $time, this.total_count),rpt_pkg::ERROR,rpt_pkg::TOP,rpt_pkg::LOG);endelse beginrpt_pkg::rpt_msg("[CMPSUCD]",$sformatf("%0t %0dth times comparing and succeeded! MCDF monitored output packet is the same with reference model output", $time, this.total_count),rpt_pkg::INFO,rpt_pkg::HIGH);endendendtaskfunction void do_report();string s;s = "\n---------------------------------------------------------------\n";s = {s, "CHECKER SUMMARY \n"}; s = {s, $sformatf("total comparison count: %0d \n", this.total_count)}; foreach(this.chnl_count[i]) s = {s, $sformatf(" channel[%0d] comparison count: %0d \n", i, this.chnl_count[i])};s = {s, $sformatf("total error count: %0d \n", this.err_count)}; foreach(this.chnl_mbs[i]) beginif(this.chnl_mbs[i].num() != 0)s = {s, $sformatf("WARNING:: chnl_mbs[%0d] is not empty! size = %0d \n", i, this.chnl_mbs[i].num())}; endif(this.fmt_mb.num() != 0)s = {s, $sformatf("WARNING:: fmt_mb is not empty! size = %0d \n", this.fmt_mb.num())}; s = {s, "---------------------------------------------------------------\n"};rpt_pkg::rpt_msg($sformatf("[%s]",this.name), s, rpt_pkg::INFO, rpt_pkg::TOP);endfunctionendclass

mcdf_env

  class mcdf_env;chnl_agent chnl_agts[3];reg_agent reg_agt;fmt_agent fmt_agt;mcdf_checker chker;protected string name;function new(string name = "mcdf_env");this.name = name;this.chker = new();foreach(chnl_agts[i]) beginthis.chnl_agts[i] = new($sformatf("chnl_agts[%0d]",i));this.chnl_agts[i].monitor.mon_mb = this.chker.chnl_mbs[i];endthis.reg_agt = new("reg_agt");this.reg_agt.monitor.mon_mb = this.chker.reg_mb;this.fmt_agt = new("fmt_agt");this.fmt_agt.monitor.mon_mb = this.chker.fmt_mb;$display("%s instantiated and connected objects", this.name);endfunctionvirtual task run();$display($sformatf("*****************%s started********************", this.name));this.do_config();forkthis.chnl_agts[0].run();this.chnl_agts[1].run();this.chnl_agts[2].run();this.reg_agt.run();this.fmt_agt.run();this.chker.run();joinendtaskvirtual function void do_config();endfunctionvirtual function void do_report();this.chker.do_report();endfunctionendclass

mcdf_base_test

  class mcdf_base_test;chnl_generator chnl_gens[3];reg_generator reg_gen;fmt_generator fmt_gen;mcdf_env env;protected string name;function new(string name = "mcdf_base_test");this.name = name;this.env = new("env");foreach(this.chnl_gens[i]) beginthis.chnl_gens[i] = new();this.env.chnl_agts[i].driver.req_mb = this.chnl_gens[i].req_mb;this.env.chnl_agts[i].driver.rsp_mb = this.chnl_gens[i].rsp_mb;endthis.reg_gen = new();this.env.reg_agt.driver.req_mb = this.reg_gen.req_mb;this.env.reg_agt.driver.rsp_mb = this.reg_gen.rsp_mb;this.fmt_gen = new();this.env.fmt_agt.driver.req_mb = this.fmt_gen.req_mb;this.env.fmt_agt.driver.rsp_mb = this.fmt_gen.rsp_mb;rpt_pkg::logname = {this.name, "_check.log"};rpt_pkg::clean_log();$display("%s instantiated and connected objects", this.name);endfunctionvirtual task run();forkenv.run();join_nonerpt_pkg::rpt_msg("[TEST]",$sformatf("=====================%s AT TIME %0t STARTED=====================", this.name, $time),rpt_pkg::INFO,rpt_pkg::HIGH);this.do_reg();this.do_formatter();this.do_data();rpt_pkg::rpt_msg("[TEST]",$sformatf("=====================%s AT TIME %0t FINISHED=====================", this.name, $time),rpt_pkg::INFO,rpt_pkg::HIGH);this.do_report();$finish();endtask// do register configurationvirtual task do_reg();endtask// do external formatter down stream slave configurationvirtual task do_formatter();endtask// do data transition from 3 channel slavesvirtual task do_data();endtask// do simulation summaryvirtual function void do_report();this.env.do_report();rpt_pkg::do_report();endfunctionvirtual function void set_interface(virtual chnl_intf ch0_vif ,virtual chnl_intf ch1_vif ,virtual chnl_intf ch2_vif ,virtual reg_intf reg_vif,virtual fmt_intf fmt_vif,virtual mcdf_intf mcdf_vif);this.env.chnl_agts[0].set_interface(ch0_vif);this.env.chnl_agts[1].set_interface(ch1_vif);this.env.chnl_agts[2].set_interface(ch2_vif);this.env.reg_agt.set_interface(reg_vif);this.env.fmt_agt.set_interface(fmt_vif);this.env.chker.set_interface(mcdf_vif);endfunctionvirtual function bit diff_value(int val1, int val2, string id = "value_compare");if(val1 != val2) beginrpt_pkg::rpt_msg("[CMPERR]", $sformatf("ERROR! %s val1 %8x != val2 %8x", id, val1, val2), rpt_pkg::ERROR, rpt_pkg::TOP);return 0;endelse beginrpt_pkg::rpt_msg("[CMPSUC]", $sformatf("SUCCESS! %s val1 %8x == val2 %8x", id, val1, val2),rpt_pkg::INFO,rpt_pkg::HIGH);return 1;endendfunctionvirtual task idle_reg();void'(reg_gen.randomize() with {cmd == `IDLE; addr == 0; data == 0;});reg_gen.start();endtaskvirtual task write_reg(bit[7:0] addr, bit[31:0] data);void'(reg_gen.randomize() with {cmd == `WRITE; addr == local::addr; data == local::data;});reg_gen.start();endtaskvirtual task read_reg(bit[7:0] addr, output bit[31:0] data);void'(reg_gen.randomize() with {cmd == `READ; addr == local::addr;});reg_gen.start();data = reg_gen.data;endtaskendclass

mcdf_data_consistence_basic_test 类,数据一致性测试。

class mcdf_data_consistence_basic_test extends mcdf_base_test;function new(string name = "mcdf_data_consistence_basic_test");super.new(name);endfunctiontask do_reg();bit[31:0] wr_val, rd_val;// slv0 with len=8,  prio=0, en=1wr_val = (1<<3)+(0<<1)+1;this.write_reg(`SLV0_RW_ADDR, wr_val);this.read_reg(`SLV0_RW_ADDR, rd_val);void'(this.diff_value(wr_val, rd_val, "SLV0_WR_REG"));// slv1 with len=16, prio=1, en=1wr_val = (2<<3)+(1<<1)+1;this.write_reg(`SLV1_RW_ADDR, wr_val);this.read_reg(`SLV1_RW_ADDR, rd_val);void'(this.diff_value(wr_val, rd_val, "SLV1_WR_REG"));// slv2 with len=32, prio=2, en=1wr_val = (3<<3)+(2<<1)+1;this.write_reg(`SLV2_RW_ADDR, wr_val);this.read_reg(`SLV2_RW_ADDR, rd_val);void'(this.diff_value(wr_val, rd_val, "SLV2_WR_REG"));// send IDLE commandthis.idle_reg();endtasktask do_formatter();void'(fmt_gen.randomize() with {fifo == LONG_FIFO; bandwidth == HIGH_WIDTH;});fmt_gen.start();endtasktask do_data();void'(chnl_gens[0].randomize() with {ntrans==100; ch_id==0; data_nidles==0; pkt_nidles==1; data_size==8; });void'(chnl_gens[1].randomize() with {ntrans==100; ch_id==1; data_nidles==1; pkt_nidles==4; data_size==16;});void'(chnl_gens[2].randomize() with {ntrans==100; ch_id==2; data_nidles==2; pkt_nidles==8; data_size==32;});forkchnl_gens[0].start();chnl_gens[1].start();chnl_gens[2].start();join#10us; // wait until all data haven been transfered through MCDFendtaskendclass

rpt_pkg.sv

package rpt_pkg;typedef enum {INFO, WARNING, ERROR, FATAL} report_t;typedef enum {LOW, MEDIUM, HIGH, TOP} severity_t;typedef enum {LOG, STOP, EXIT} action_t;static severity_t svrt = LOW;static string logname = "report.log";static int info_count = 0;static int warning_count = 0;static int error_count = 0;static int fatal_count = 0;function void rpt_msg(string src, string i, report_t r=INFO, severity_t s=LOW, action_t a=LOG);integer logf;string msg;case(r)INFO: info_count++;WARNING: warning_count++;ERROR: error_count++;FATAL: fatal_count++;endcaseif(s >= svrt) beginmsg = $sformatf("@%0t [%s] %s : %s", $time, r, src, i);logf = $fopen(logname, "a+");$display(msg);$fwrite(logf, $sformatf("%s\n", msg));$fclose(logf);if(a == STOP) begin$stop();endelse if(a == EXIT) begin$finish();endendendfunctionfunction void do_report();string s;s = "\n---------------------------------------------------------------\n";s = {s, "REPORT SUMMARY\n"}; s = {s, $sformatf("info count: %0d \n", info_count)}; s = {s, $sformatf("warning count: %0d \n", warning_count)}; s = {s, $sformatf("error count: %0d \n", error_count)}; s = {s, $sformatf("fatal count: %0d \n", fatal_count)}; s = {s, "---------------------------------------------------------------\n"};rpt_msg("[REPORT]", s, rpt_pkg::INFO, rpt_pkg::TOP);endfunctionfunction void clean_log();integer logf;logf = $fopen(logname, "w");$fclose(logf);endfunction
endpackage

四、运行仿真

vsim -novopt -classdebug -solvefaildebug -sv_seed 0 +TESTNAME=mcdf_data_consistence_basic_test -l mcdf_data_consistence_basic_test.log work.tb
log -r /*
run -all

仿真器会不停的发送激励、监测激励、数据比较

五、数据通道开关检查

在Lab4中,数据通道的开关,在数据通道关闭的情况下,mcdf_checker应该不会收到输入端或者输出端的监测数据,因此不应该出现数据比较的信息。那么在这种情况下如何判断这个测试通过?而且还需要检查一个简单的时序,即当slave channel被关闭时,当valid拉高时,ready信号不应该出现拉高的情况,否则设计是有问题的,因为数据可能没有被真正写入到FIFO,或者slave channel此时并没有被真正关闭。

针对这个问题,在mcdf_checker,将en信号检测到,将其传入mcdf_checker,同时也将3个chnl_intf传入mcdf_checker,这样mcdf_checker可以观测到所需的validreadyen信号,来完成这个检查。

do_channel_disable_check()

    task do_channel_disable_check(int id);forever begin@(posedge this.mcdf_vif.clk iff (this.mcdf_vif.rstn && this.mcdf_vif.mon_ck.chnl_en[id]===0));if(this.chnl_vifs[id].mon_ck.ch_valid===1 && this.chnl_vifs[id].mon_ck.ch_ready===1)rpt_pkg::rpt_msg("[CHKERR]", $sformatf("ERROR! %0t when channel disabled, ready signal raised when valid high",$time), rpt_pkg::ERROR, rpt_pkg::TOP);endendtask

通过forever不断的监测,在每一个时钟上升沿的时候,并且复位信号已经复位的情况下,要监测chal_en[id]这个信号,这个chal_en[id]信号是从设计里面监测到的,即把这个信号放到mcdf_vif中监测。mcdf_vif会监测一些硬件信号,然后把监测到的硬件信号传给内部的验证组件。

mcdf_intf()

interface mcdf_intf(input clk, input rstn);// To define those signals which do not exsit in// reg_if, chnl_if, arb_if or fmt_iflogic chnl_en[3];clocking mon_ck @(posedge clk);default input #1ns output #1ns;input chnl_en;endclocking
endinterface

然后例化 mcdf_intf()并且从DUT中抓取信号

  mcdf_intf mcdf_if(.*);// mcdf interface monitoring MCDF ports and signalsassign mcdf_if.chnl_en[0] = tb.dut.ctrl_regs_inst.slv0_en_o;assign mcdf_if.chnl_en[1] = tb.dut.ctrl_regs_inst.slv1_en_o;assign mcdf_if.chnl_en[2] = tb.dut.ctrl_regs_inst.slv2_en_o;

slv0_en_oslv1_en_oslv2_en_o在设计中,这三个bit分别送给设计中的Slave0Slave1Slave2用来控制数据通道开关闭。mcdf_if会抓取到这三个bit的信号,放到chnl_en[3]中,mcdf_checker会时刻监测这三个内部信号。检测到chnl_en === 0 时,那么当ch_valid === 1的情况下,ch_ready就不应该为1,即当数据通道关闭的情况下,valid和ready信号不应该同时拉高。否则将会报错误。

除了监测en内部信号,还可以调用mcdf_refmod里面的get_field_value()得到RW_EN,即代码改成

@(posedge this.mcdf_vif.clk iff (this.mcdf_vif.rstn && refmod.get_field_value(id, RW_EN));

六、优先级的检查

在Lab4中,对于优先级的检查,mcdf_checker依然无法从mcdf_refmod的预测数据中获取数据包前后的信息,也就是说mcdf_checker无法判断最终从mcdf发送出的数据是否符合了优先级的数据包发送顺序,那么将需要观测arbiter信号在mcdf_intf中声明并且观测。

do_arbiter_priority_check()

task do_arbiter_priority_check();int id;forever begin@(posedge this.arb_vif.clk iff (this.arb_vif.rstn && this.arb_vif.mon_ck.f2a_id_req===1));id = this.get_slave_id_with_prio();if(id >= 0) begin@(posedge this.arb_vif.clk);if(this.arb_vif.mon_ck.a2s_acks[id] !== 1)rpt_pkg::rpt_msg("[CHKERR]",$sformatf("ERROR! %0t arbiter received f2a_id_req===1 and channel[%0d] raising request with high priority, but is not granted by arbiter", $time, id),rpt_pkg::ERROR,rpt_pkg::TOP);endendendtask

当时钟的上升沿到来,并且f2a_id_req===1,表示formatter发送请求给arbiter准备取数据,然后调用get_slave_id_with_prio()判断哪个id的优先级最高。

get_slave_id_with_prio()

    function int get_slave_id_with_prio();int id=-1;int prio=999;foreach(this.arb_vif.mon_ck.slv_prios[i]) beginif(this.arb_vif.mon_ck.slv_prios[i] < prio && this.arb_vif.mon_ck.slv_reqs[i]===1) beginid = i;prio = this.arb_vif.mon_ck.slv_prios[i];endendreturn id;endfunction

得到最高优先级的那个slave之后,等待下一个时钟上升沿,判断arbiter给slave的ack信号是否为1,即a2s_acks[id] !== 1。通过仲裁arbiter得到的slave的id和对应的ack[id]相比较,看是否是一致的,不一致则会报错。即需要判断当req发送请求之后,ack是否拉高同意请求。

MCDF实验——Lab4相关推荐

  1. 计算机网络自顶向下 Wireshark实验 Lab4 TCP

    计算机网络自顶向下 Wireshark实验 Lab4 TCP 不写答案,本文章只记录 任务 和 问题 开始Wireshark Lab TCP 先在Wireshark Lab官网下载相应文档:https ...

  2. MCDF实验4(4)

    目录 引言:接着上篇的MCDF实验4(3),解释一下添加的检查 1)通道 en=0 时的检查 2)arbiter 的仲裁功能的检查 在tb.sv 中 连接信号 引言:接着上篇的MCDF实验4(3),解 ...

  3. [操作系统实验lab4]实验报告

    实验概况 在开始实验之前,先对实验整体有个大概的了解,这样能让我们更好地进行实验. 我们本次实验需要补充的内容包括一整套以sys开头的系统调用函数,其中包括了进程间通信需要的一些系统调用如sys_ip ...

  4. MCDF实验——Lab5

    Lab5主要完成如何定义覆盖率,如何从验证计划到测试用例的实现,最后再到覆盖率的量化.验证量化分为代码覆盖率和功能覆盖率. 一.编译 在编译过程中,需要对于设计相关的文件设置额外的覆盖率编译选项. 只 ...

  5. 《计算机网络自顶向下》Wireshark实验 Lab4 TCP

    文章目录 专栏博客链接 前引 Lab4 TCP 查阅Wireshark Lab官网 获取Lab文档 Q&A 1 所作工作 Q&A 1 专栏博客链接 <计算机网络自顶向下>W ...

  6. MCDF实验_lab0(0)

    目录 一.MCDF功能描述[^1] MCDF结构 slave端口时序 formater端口时序 寄存器时序 二.代码分析 时间单位 信号 例化 产生时钟 产生复位 发送激励 三.Questasim的M ...

  7. MCDF实验_lab1(1)

    目录 一.问题 二.实验要求 三.代码分析 时间单位 信号 例化 产生时钟 产生复位 发送激励模块 产生数据 实例化slave模块 发送激励 三.Questasim的Makefile[^2] 四.波形 ...

  8. MCDF实验_lab4(4)

    目录 一.框架图 二.代码分析 reg_chnl reg_trans,传输的数据包 reg_generator reg_driver reg_monitor reg_agent fmt_pkg fmt ...

  9. MCDF 实验4 (1)

    目录 fmt_pkg.sv 代码分析 fmt_pkg.sv 中的 fmt_driver do_consume() 的代码解析 ​ do_receive()  的代码解析 do_config() 的代码 ...

最新文章

  1. npm i和npm install的区别
  2. SAP PM 初级系列3 - 主数据相关的基础设置
  3. MySQL数据库存储过程动态表建立(PREPARE)
  4. tensorflow教程 开始——Premade Estimators(预制评估器)
  5. android 显示进度的按钮
  6. [JavaWeb-MySQL]多表查询概述
  7. 8.String、StringBuffer、enum枚举
  8. maven 打包部署时访问远程仓库中没有的jar
  9. 部分 I. 教程_第 2 章 SQL语言_2.2. 概念
  10. 力扣--125验证回文串/680验证回文字符串II
  11. Bailian2886 能被3除尽的数之和【进制】
  12. SimpleDateFormat的使用问题
  13. 信息图表是如何炼成的(三):阶层结构与isometric
  14. 信息系统项目管理师计算题(三点估算)
  15. 2022年最好的游戏引擎是什么?
  16. Java代码实现点赞功能
  17. 基于单片机的电压电流表设计
  18. Pandas入门篇:Pandas基础
  19. 8086CPU指令系统 串操作指令和处理机控制指令
  20. 电脑开机时,需选择启动项f1/f2/f5, 需按f1才能正常启动计算机

热门文章

  1. 使用pelican搭建一个Jupyter Notebook数据科学博客
  2. Android 7.0 SystemUI 状态/导航栏的隐藏与显示
  3. 打破双亲委派的自定义ClassLoader
  4. calendar类的日期加减
  5. 如何理解Web语义化
  6. JavaScript学习笔记——DOM
  7. Java错题归纳day12
  8. 使用xpath时候出现AttributeError: ‘list‘ object has no attribute ‘strip‘解决方法
  9. 我的世界服务器无线重启咋办,我的世界》服务器重启方法介绍 如何重启服务器...
  10. 在计算机组装中如何判断硬件的型号,电脑配置如何看?查看电脑配置好坏的方法 (值得收藏学习)...