mirror of
https://github.com/MPSU/APS.git
synced 2025-09-15 17:20:10 +00:00
ЛР4. Рефактор демонстрационного модуля
Демонстрационный модуль теперь только один --------- Co-authored-by: Andrei Solodovnikov <VoultBoy@yandex.ru>
This commit is contained in:
@@ -2,91 +2,443 @@
|
||||
* Project Name : Architectures of Processor Systems (APS) lab work
|
||||
* Organization : National Research University of Electronic Technology (MIET)
|
||||
* Department : Institute of Microdevices and Control Systems
|
||||
* Author(s) : Nikita Bulavin
|
||||
* Email(s) : nekkit6@edu.miet.ru
|
||||
* Author(s) : Alexander Kharlamov
|
||||
* Email(s) : sasha_xarlamov@org.miet.ru
|
||||
|
||||
See https://github.com/MPSU/APS/blob/master/LICENSE file for licensing details.
|
||||
* ------------------------------------------------------------------------------
|
||||
*/
|
||||
module nexys_CYBERcobra_dz(
|
||||
input CLK100,
|
||||
input resetn,
|
||||
input BTND,
|
||||
input [15:0] SW,
|
||||
output CA, CB, CC, CD, CE, CF, CG,
|
||||
output [7:0] AN
|
||||
typedef enum {
|
||||
INSTR_ALU , // branch and computational
|
||||
INSTR_LI , // const load
|
||||
INSTR_IN , // periphery load
|
||||
INSTR_JUMP ,
|
||||
INSTR_NOP // ws == 3
|
||||
} Instruction_type;
|
||||
|
||||
typedef enum {
|
||||
CH_0 = 0,
|
||||
CH_1,
|
||||
CH_2,
|
||||
CH_3,
|
||||
CH_4,
|
||||
CH_5,
|
||||
CH_6,
|
||||
CH_7,
|
||||
CH_8,
|
||||
CH_9,
|
||||
CH_A,
|
||||
CH_b,
|
||||
CH_c,
|
||||
CH_d,
|
||||
CH_E,
|
||||
CH_F,
|
||||
CH_G,
|
||||
CH_L,
|
||||
CH_n,
|
||||
CH_o,
|
||||
CH_r,
|
||||
CH_S,
|
||||
CH_t,
|
||||
CH_u,
|
||||
CH_X,
|
||||
CH_P,
|
||||
CH_J,
|
||||
CH_q,
|
||||
CH_i,
|
||||
CH_m,
|
||||
|
||||
CH_SPACE
|
||||
} Char;
|
||||
|
||||
typedef struct {
|
||||
logic ca;
|
||||
logic cb;
|
||||
logic cc;
|
||||
logic cd;
|
||||
logic ce;
|
||||
logic cf;
|
||||
logic cg;
|
||||
logic dp;
|
||||
} Semseg;
|
||||
|
||||
module nexys_CYBERcobra(
|
||||
input logic clk_i,
|
||||
input logic arstn_i,
|
||||
input logic [15:0] sw_i,
|
||||
input logic btnd_i,
|
||||
output logic [15:0] led_o,
|
||||
output logic ca_o,
|
||||
output logic cb_o,
|
||||
output logic cc_o,
|
||||
output logic cd_o,
|
||||
output logic ce_o,
|
||||
output logic cf_o,
|
||||
output logic cg_o,
|
||||
output logic dp_o,
|
||||
output logic [ 7:0] an_o
|
||||
);
|
||||
|
||||
logic [31:0] cobra_out;
|
||||
|
||||
logic btnd_sync;
|
||||
sync sync (
|
||||
.clk_i ,
|
||||
.data_i (btnd_i ),
|
||||
.data_o (btnd_sync)
|
||||
);
|
||||
logic btnd_debounce;
|
||||
debounce debounce (
|
||||
.clk_i ,
|
||||
.arstn_i ,
|
||||
.data_i (btnd_sync ),
|
||||
.data_o (btnd_debounce)
|
||||
);
|
||||
logic bufg_clk;
|
||||
BUFG dut_bufg(
|
||||
.I (btnd_debounce),
|
||||
.O (bufg_clk )
|
||||
);
|
||||
|
||||
CYBERcobra dut (
|
||||
.clk_i (bufg_clk ),
|
||||
.rst_i (!arstn_i ),
|
||||
.sw_i (sw_i ),
|
||||
.out_o (cobra_out )
|
||||
);
|
||||
|
||||
logic [31:0] instr_addr;
|
||||
logic [31:0] instr;
|
||||
assign instr_addr = dut.imem.addr_i;
|
||||
assign instr = dut.imem.read_data_o;
|
||||
|
||||
import alu_opcodes_pkg::*;
|
||||
|
||||
Instruction_type instr_type;
|
||||
logic [ALU_OP_WIDTH-1:0] alu_op;
|
||||
logic illegal_instr;
|
||||
nexys_CYBERcobra_decoder nexys_CYBERcobra_decoder (
|
||||
.instr_i (instr ),
|
||||
.instr_type_o (instr_type ),
|
||||
.alu_op_o (alu_op ),
|
||||
.illegal_instr_o (illegal_instr)
|
||||
);
|
||||
|
||||
Char op_chars[0:3];
|
||||
always_comb begin
|
||||
op_chars = '{4{CH_SPACE}};
|
||||
|
||||
case (instr_type)
|
||||
INSTR_ALU:
|
||||
case (alu_op)
|
||||
ALU_ADD : op_chars[0:2] = '{CH_A, CH_d, CH_d};
|
||||
ALU_SUB : op_chars[0:2] = '{CH_S, CH_u, CH_b};
|
||||
ALU_XOR : op_chars[0:2] = '{CH_X, CH_o, CH_r};
|
||||
ALU_OR : op_chars[0:1] = '{CH_o, CH_r};
|
||||
ALU_AND : op_chars[0:2] = '{CH_A, CH_n, CH_d};
|
||||
ALU_SRA : op_chars[0:2] = '{CH_S, CH_r, CH_A};
|
||||
ALU_SRL : op_chars[0:2] = '{CH_S, CH_r, CH_L};
|
||||
ALU_SLL : op_chars[0:2] = '{CH_S, CH_L, CH_L};
|
||||
ALU_LTS : op_chars[0:2] = '{CH_L, CH_t, CH_S};
|
||||
ALU_LTU : op_chars[0:2] = '{CH_L, CH_t, CH_u};
|
||||
ALU_GES : op_chars[0:2] = '{CH_G, CH_E, CH_S};
|
||||
ALU_GEU : op_chars[0:2] = '{CH_G, CH_E, CH_u};
|
||||
ALU_EQ : op_chars[0:1] = '{CH_E, CH_q};
|
||||
ALU_NE : op_chars[0:1] = '{CH_n, CH_E};
|
||||
ALU_SLTS: op_chars = '{CH_S, CH_L, CH_t, CH_S};
|
||||
ALU_SLTU: op_chars = '{CH_S, CH_L, CH_t, CH_u};
|
||||
|
||||
default : ;
|
||||
endcase
|
||||
INSTR_LI : op_chars[0:1] = '{CH_L, CH_i};
|
||||
INSTR_JUMP: op_chars = '{CH_J, CH_u, CH_m, CH_P};
|
||||
INSTR_NOP : op_chars[0:2] = '{CH_n, CH_o, CH_P};
|
||||
INSTR_IN : op_chars[0:1] = '{CH_i, CH_n};
|
||||
endcase
|
||||
end
|
||||
|
||||
Char all_chars[0:7];
|
||||
assign all_chars[0:3] = {
|
||||
Char'(led_o[7:4]) ,
|
||||
Char'(led_o[3:0]) ,
|
||||
Char'(instr_addr[7:4]),
|
||||
Char'(instr_addr[3:0])
|
||||
};
|
||||
localparam Char ILL_INSTR_MSG[0:3] = '{CH_i, CH_L, CH_L, CH_SPACE};
|
||||
assign all_chars[4:7] = illegal_instr ? ILL_INSTR_MSG : op_chars;
|
||||
|
||||
Semseg all_semsegs[0:7];
|
||||
for (genvar semseg_num = 0; semseg_num < 8; ++semseg_num) begin : CHAR2SEMSEG_GEN
|
||||
char2semseg char2semseg (
|
||||
.char_i (all_chars [semseg_num]),
|
||||
.semseg_o (all_semsegs[semseg_num])
|
||||
);
|
||||
|
||||
CYBERcobra dut(
|
||||
.clk_i(btn),
|
||||
.rst_i(!resetn),
|
||||
.sw_i(SW[15:0]),
|
||||
.out_o(out)
|
||||
);
|
||||
|
||||
localparam pwm = 1000;
|
||||
reg [9:0] counter;
|
||||
reg [3:0] semseg;
|
||||
reg [7:0] ANreg;
|
||||
reg CAr, CBr, CCr, CDr, CEr, CFr, CGr;
|
||||
reg btn;
|
||||
wire [31:0] out;
|
||||
|
||||
assign AN[7:0] = ANreg[7:0];
|
||||
assign {CA, CB, CC, CD, CE, CF, CG} = {CAr, CBr, CCr, CDr, CEr, CFr, CGr};
|
||||
end
|
||||
|
||||
|
||||
always @(posedge CLK100) begin
|
||||
if (!resetn) begin
|
||||
counter <= 'b0;
|
||||
ANreg[7:0] <= 8'b11111111;
|
||||
{CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b1111111;
|
||||
btn <= BTND;
|
||||
Semseg all_semsegs_dotted[0:7];
|
||||
assign all_semsegs_dotted[0] = all_semsegs[0];
|
||||
assign all_semsegs_dotted[2:7] = all_semsegs[2:7];
|
||||
assign all_semsegs_dotted[1].ca = all_semsegs[1].ca;
|
||||
assign all_semsegs_dotted[1].cb = all_semsegs[1].cb;
|
||||
assign all_semsegs_dotted[1].cc = all_semsegs[1].cc;
|
||||
assign all_semsegs_dotted[1].cd = all_semsegs[1].cd;
|
||||
assign all_semsegs_dotted[1].ce = all_semsegs[1].ce;
|
||||
assign all_semsegs_dotted[1].cf = all_semsegs[1].cf;
|
||||
assign all_semsegs_dotted[1].cg = all_semsegs[1].cg;
|
||||
assign all_semsegs_dotted[1].dp = 1'b0;
|
||||
|
||||
Semseg current_semseg;
|
||||
logic [7:0] an;
|
||||
semseg_one2many semseg_one2many (
|
||||
.clk100m_i (clk_i ),
|
||||
.arstn_i (arstn_i ),
|
||||
.all_semsegs_i (all_semsegs_dotted),
|
||||
.current_semseg_o (current_semseg ),
|
||||
.an_o (an )
|
||||
);
|
||||
|
||||
assign ca_o = current_semseg.ca;
|
||||
assign cb_o = current_semseg.cb;
|
||||
assign cc_o = current_semseg.cc;
|
||||
assign cd_o = current_semseg.cd;
|
||||
assign ce_o = current_semseg.ce;
|
||||
assign cf_o = current_semseg.cf;
|
||||
assign cg_o = current_semseg.cg;
|
||||
assign dp_o = current_semseg.dp;
|
||||
|
||||
assign an_o = an;
|
||||
|
||||
assign led_o = cobra_out[15:0];
|
||||
|
||||
endmodule
|
||||
|
||||
module nexys_CYBERcobra_decoder
|
||||
import alu_opcodes_pkg::*;
|
||||
(
|
||||
input logic [31:0] instr_i,
|
||||
output Instruction_type instr_type_o,
|
||||
output logic [ALU_OP_WIDTH-1:0] alu_op_o,
|
||||
output logic illegal_instr_o
|
||||
);
|
||||
|
||||
logic j;
|
||||
logic b;
|
||||
logic [1:0] ws;
|
||||
|
||||
assign j = instr_i[31];
|
||||
assign b = instr_i[30];
|
||||
assign ws = instr_i[29:28];
|
||||
|
||||
logic is_branch_instr;
|
||||
assign is_branch_instr = b;
|
||||
|
||||
always_comb begin
|
||||
instr_type_o = INSTR_NOP;
|
||||
|
||||
if (j) begin
|
||||
instr_type_o = INSTR_JUMP;
|
||||
end else if (b) begin
|
||||
instr_type_o = INSTR_ALU;
|
||||
end else begin
|
||||
case (ws)
|
||||
2'd0: instr_type_o = INSTR_LI;
|
||||
2'd1: instr_type_o = INSTR_ALU;
|
||||
2'd2: instr_type_o = INSTR_IN;
|
||||
2'd3: instr_type_o = INSTR_NOP;
|
||||
endcase
|
||||
end
|
||||
else begin
|
||||
btn <= BTND;
|
||||
if (counter < pwm) counter = counter + 'b1;
|
||||
else begin
|
||||
counter = 'b0;
|
||||
ANreg[1] <= ANreg[0];
|
||||
ANreg[2] <= ANreg[1];
|
||||
ANreg[3] <= ANreg[2];
|
||||
ANreg[4] <= ANreg[3];
|
||||
ANreg[5] <= ANreg[4];
|
||||
ANreg[6] <= ANreg[5];
|
||||
ANreg[7] <= ANreg[6];
|
||||
ANreg[0] <= !(ANreg[6:0] == 7'b1111111);
|
||||
end
|
||||
case (1'b0)
|
||||
ANreg[0]: semseg <= out[3 : 0];
|
||||
ANreg[1]: semseg <= out[7 : 4];
|
||||
ANreg[2]: semseg <= out[11: 8];
|
||||
ANreg[3]: semseg <= out[15:12];
|
||||
ANreg[4]: semseg <= out[19:16];
|
||||
ANreg[5]: semseg <= out[23:20];
|
||||
ANreg[6]: semseg <= out[27:24];
|
||||
ANreg[7]: semseg <= out[31:28];
|
||||
endcase
|
||||
case (semseg)
|
||||
4'h0: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0000001;
|
||||
4'h1: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b1001111;
|
||||
4'h2: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0010010;
|
||||
4'h3: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0000110;
|
||||
4'h4: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b1001100;
|
||||
4'h5: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0100100;
|
||||
4'h6: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0100000;
|
||||
4'h7: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0001111;
|
||||
4'h8: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0000000;
|
||||
4'h9: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0000100;
|
||||
4'hA: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0001000;
|
||||
4'hB: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b1100000;
|
||||
4'hC: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0110001;
|
||||
4'hD: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b1000010;
|
||||
4'hE: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0110000;
|
||||
4'hF: {CAr, CBr, CCr, CDr, CEr, CFr, CGr} <= 7'b0111000;
|
||||
default: {CAr,CBr,CCr,CDr, CEr, CFr, CGr} <= 7'b0111111;
|
||||
endcase
|
||||
end
|
||||
end
|
||||
|
||||
assign alu_op_o = instr_i[27:23];
|
||||
|
||||
import alu_opcodes_pkg::*;
|
||||
|
||||
typedef enum {
|
||||
ALU_OP_BRANCH,
|
||||
ALU_OP_COMPUTATIONAL,
|
||||
ALU_OP_ILLEGAL
|
||||
} Alu_op_type;
|
||||
Alu_op_type alu_op_type;
|
||||
always_comb begin
|
||||
alu_op_type = ALU_OP_ILLEGAL;
|
||||
|
||||
case (alu_op_o) inside
|
||||
ALU_LTS,
|
||||
ALU_LTU,
|
||||
ALU_GES,
|
||||
ALU_GEU,
|
||||
ALU_EQ ,
|
||||
ALU_NE : alu_op_type = ALU_OP_BRANCH;
|
||||
|
||||
ALU_ADD ,
|
||||
ALU_SUB ,
|
||||
ALU_XOR ,
|
||||
ALU_OR ,
|
||||
ALU_AND ,
|
||||
ALU_SRA ,
|
||||
ALU_SRL ,
|
||||
ALU_SLL ,
|
||||
ALU_SLTS,
|
||||
ALU_SLTU: alu_op_type = ALU_OP_COMPUTATIONAL;
|
||||
|
||||
default : alu_op_type = ALU_OP_ILLEGAL;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign illegal_instr_o = (instr_type_o == INSTR_ALU) && ((alu_op_type == ALU_OP_ILLEGAL) ||
|
||||
((alu_op_type == ALU_OP_BRANCH) ^ is_branch_instr));
|
||||
endmodule
|
||||
|
||||
module char2semseg #(
|
||||
parameter bit HEX_ONLY = 1'b0
|
||||
) (
|
||||
input Char char_i,
|
||||
output Semseg semseg_o
|
||||
);
|
||||
|
||||
localparam bit [6:0] BLANK = '1;
|
||||
|
||||
logic [6:0] semseg;
|
||||
always_comb begin
|
||||
case (char_i)
|
||||
CH_0 : semseg = ~7'h3F;
|
||||
CH_1 : semseg = ~7'h06;
|
||||
CH_2 : semseg = ~7'h5B;
|
||||
CH_3 : semseg = ~7'h4F;
|
||||
CH_4 : semseg = ~7'h66;
|
||||
CH_5 : semseg = ~7'h6D;
|
||||
CH_6 : semseg = ~7'h7D;
|
||||
CH_7 : semseg = ~7'h07;
|
||||
CH_8 : semseg = ~7'h7F;
|
||||
CH_9 : semseg = ~7'h6F;
|
||||
CH_A : semseg = ~7'h5F;
|
||||
CH_b : semseg = ~7'h7C;
|
||||
CH_c : semseg = ~7'h58;
|
||||
CH_d : semseg = ~7'h5E;
|
||||
CH_E : semseg = ~7'h79;
|
||||
CH_F : semseg = ~7'h71;
|
||||
CH_G : semseg = ~7'h3D;
|
||||
CH_L : semseg = ~7'h38;
|
||||
CH_n : semseg = ~7'h54;
|
||||
CH_o : semseg = ~7'h5C;
|
||||
CH_r : semseg = ~7'h50;
|
||||
CH_S : semseg = ~7'h64;
|
||||
CH_t : semseg = ~7'h78;
|
||||
CH_u : semseg = ~7'h1C;
|
||||
CH_X : semseg = ~7'h76;
|
||||
CH_P : semseg = ~7'h73;
|
||||
CH_J : semseg = ~7'h1E;
|
||||
CH_q : semseg = ~7'h67;
|
||||
CH_i : semseg = ~7'h30;
|
||||
CH_m : semseg = ~7'h77;
|
||||
default : semseg = BLANK;
|
||||
endcase
|
||||
end
|
||||
|
||||
assign semseg_o.ca = semseg[0];
|
||||
assign semseg_o.cb = semseg[1];
|
||||
assign semseg_o.cc = semseg[2];
|
||||
assign semseg_o.cd = semseg[3];
|
||||
assign semseg_o.ce = semseg[4];
|
||||
assign semseg_o.cf = semseg[5];
|
||||
assign semseg_o.cg = semseg[6];
|
||||
assign semseg_o.dp = 1'b1;
|
||||
|
||||
endmodule
|
||||
|
||||
module semseg_one2many #(
|
||||
parameter int unsigned SEMSEGS_NUM = 8
|
||||
) (
|
||||
input Semseg all_semsegs_i[0:SEMSEGS_NUM-1],
|
||||
input logic clk100m_i,
|
||||
input logic arstn_i,
|
||||
output Semseg current_semseg_o,
|
||||
output logic [7:0] an_o
|
||||
);
|
||||
logic clk_i;
|
||||
assign clk_i = clk100m_i;
|
||||
|
||||
localparam int COUNTER_WIDTH = 10;
|
||||
logic [COUNTER_WIDTH-1:0] counter_next;
|
||||
logic [COUNTER_WIDTH-1:0] counter_ff;
|
||||
assign counter_next = counter_ff + COUNTER_WIDTH'('b1);
|
||||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||||
if (!arstn_i) counter_ff <= '0;
|
||||
else counter_ff <= counter_next;
|
||||
end
|
||||
|
||||
logic [7:0] an_ff;
|
||||
logic [7:0] an_next;
|
||||
logic an_en;
|
||||
assign an_next = {an_ff[$left(an_ff)-1:0], an_ff[$left(an_ff)]};
|
||||
assign an_en = ~|counter_ff;
|
||||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||||
if (!arstn_i) an_ff <= ~8'b1;
|
||||
else if (an_en) an_ff <= an_next;
|
||||
end
|
||||
|
||||
Semseg current_semseg;
|
||||
always_comb begin
|
||||
unique case (1'b0)
|
||||
an_ff[0]: current_semseg = all_semsegs_i[7];
|
||||
an_ff[1]: current_semseg = all_semsegs_i[6];
|
||||
an_ff[2]: current_semseg = all_semsegs_i[5];
|
||||
an_ff[3]: current_semseg = all_semsegs_i[4];
|
||||
an_ff[4]: current_semseg = all_semsegs_i[3];
|
||||
an_ff[5]: current_semseg = all_semsegs_i[2];
|
||||
an_ff[6]: current_semseg = all_semsegs_i[1];
|
||||
an_ff[7]: current_semseg = all_semsegs_i[0];
|
||||
endcase
|
||||
end
|
||||
|
||||
assign current_semseg_o = current_semseg;
|
||||
|
||||
assign an_o = an_ff;
|
||||
|
||||
endmodule
|
||||
|
||||
module debounce #(
|
||||
parameter int unsigned MAX_COUNT = 10000
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic arstn_i,
|
||||
input logic data_i,
|
||||
output logic data_o
|
||||
);
|
||||
|
||||
localparam int COUNTER_WIDTH = $clog2(MAX_COUNT);
|
||||
logic [COUNTER_WIDTH-1:0] counter_next;
|
||||
logic [COUNTER_WIDTH-1:0] counter_ff;
|
||||
assign counter_next = (data_o != data_i) ? counter_ff - COUNTER_WIDTH'('b1) :
|
||||
COUNTER_WIDTH'(MAX_COUNT);
|
||||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||||
if (!arstn_i) counter_ff <= COUNTER_WIDTH'(MAX_COUNT);
|
||||
else counter_ff <= counter_next;
|
||||
end
|
||||
|
||||
always_ff @(posedge clk_i or negedge arstn_i) begin
|
||||
if (!arstn_i) data_o <= '0;
|
||||
else if (~|counter_ff) data_o <= data_i;
|
||||
end
|
||||
|
||||
endmodule
|
||||
|
||||
module sync #(
|
||||
parameter int unsigned SYNC_STAGES = 3
|
||||
) (
|
||||
input logic clk_i,
|
||||
input logic data_i,
|
||||
output logic data_o
|
||||
);
|
||||
|
||||
logic [SYNC_STAGES-1:0] sync_buffer_ff;
|
||||
logic [SYNC_STAGES-1:0] sync_buffer_next;
|
||||
assign sync_buffer_next = {sync_buffer_ff[$left(sync_buffer_ff)-1:0], data_i};
|
||||
always_ff @(posedge clk_i) begin
|
||||
sync_buffer_ff <= sync_buffer_next;
|
||||
end
|
||||
|
||||
assign data_o = sync_buffer_ff[$left(sync_buffer_ff)];
|
||||
|
||||
endmodule
|
||||
|
Reference in New Issue
Block a user