summaryrefslogtreecommitdiff
path: root/rtl/core/core_decode_mux.sv
diff options
context:
space:
mode:
Diffstat (limited to 'rtl/core/core_decode_mux.sv')
-rw-r--r--rtl/core/core_decode_mux.sv295
1 files changed, 295 insertions, 0 deletions
diff --git a/rtl/core/core_decode_mux.sv b/rtl/core/core_decode_mux.sv
new file mode 100644
index 0000000..f90ee49
--- /dev/null
+++ b/rtl/core/core_decode_mux.sv
@@ -0,0 +1,295 @@
+`include "core/isa.sv"
+`include "core/uarch.sv"
+
+module core_decode_mux
+(
+ input word insn,
+
+ input logic branch_link,
+
+ input snd_decode snd,
+ input logic snd_undefined,
+
+ input data_decode data,
+ input logic data_writeback,
+ data_conditional,
+ data_update_flags,
+ data_restore_spsr,
+ data_is_imm,
+ data_shift_by_reg_if_reg,
+
+ input ldst_decode ldst_misc,
+ ldst_single,
+ ldst_multiple,
+ ldst_exclusive,
+ input logic ldst_single_is_imm,
+ ldst_misc_off_is_imm,
+ input reg_num ldst_ex_snd_r,
+ ldst_misc_off_reg,
+ input logic[7:0] ldst_misc_off_imm,
+ input logic ldst_mult_restore_spsr,
+ input data_decode data_ldst,
+
+ input logic mul_update_flags,
+ input reg_num mul_rd,
+ mul_rs,
+ mul_rm,
+
+ input coproc_decode dec_coproc,
+ input logic coproc_writeback,
+ coproc_update_flags,
+ input reg_num coproc_rd,
+
+ input logic msr_spsr,
+ msr_is_imm,
+ mrs_spsr,
+ input reg_num mrs_rd,
+ input msr_mask msr_fields,
+
+ output snd_decode dec_snd,
+ output data_decode dec_data,
+ output ldst_decode dec_ldst,
+ ldst_addr,
+ output logic execute,
+ undefined,
+ conditional,
+ writeback,
+ branch,
+ ldst,
+ mul,
+ psr,
+ swi,
+ coproc,
+ bkpt,
+ psr_saved,
+ psr_write,
+ psr_wr_flags,
+ psr_wr_control,
+ update_flags,
+ restore_spsr,
+ snd_is_imm,
+ snd_ror_if_imm,
+ snd_shift_by_reg_if_reg
+);
+
+ always_comb begin
+ mul = 0;
+ swi = 0;
+ psr = 0;
+ ldst = 0;
+ bkpt = 0;
+ branch = 0;
+ coproc = 0;
+ execute = 1;
+ undefined = 0;
+ writeback = 0;
+ conditional = 0;
+ restore_spsr = 0;
+
+ psr_saved = 0;
+ psr_write = 0;
+ update_flags = 0;
+ psr_wr_flags = 1;
+ psr_wr_control = 1;
+
+ dec_data = {($bits(dec_data)){1'bx}};
+ dec_data.uses_rn = 1;
+
+ dec_snd = {$bits(dec_snd){1'bx}};
+ dec_snd.shr = 0;
+ dec_snd.ror = 0;
+ dec_snd.is_imm = 1;
+ dec_snd.shift_imm = {$bits(dec_snd.shift_imm){1'b0}};
+ dec_snd.shift_by_reg = 0;
+
+ snd_is_imm = 1'bx;
+ snd_ror_if_imm = 1'bx;
+ snd_shift_by_reg_if_reg = 1'bx;
+
+ dec_ldst = {($bits(dec_ldst)){1'bx}};
+ ldst_addr = {($bits(ldst_addr)){1'bx}};
+
+ // El orden de los casos es importante, NO CAMBIAR
+ priority casez(insn `FIELD_OP)
+ `GROUP_B: begin
+ branch = 1;
+ dec_data.uses_rn = branch_link;
+
+ if(branch_link) begin
+ dec_data.op = `ALU_SUB;
+ dec_data.rd = `R14;
+ dec_data.rn = `R15;
+ dec_snd.imm = 12'd4;
+ writeback = 1;
+ end
+ end
+
+ `GROUP_MUL: begin
+ mul = 1;
+
+ dec_data.rd = mul_rd;
+ dec_data.rn = mul_rs;
+
+ dec_snd.is_imm = 0;
+ dec_snd.r = mul_rm;
+
+ writeback = 1;
+ update_flags = mul_update_flags;
+ end
+
+ `GROUP_LDST_EX: begin
+ dec_ldst = ldst_exclusive;
+ ldst_addr = ldst_exclusive;
+
+ dec_snd.r = ldst_ex_snd_r;
+ dec_snd.is_imm = ldst_exclusive.load;
+ end
+
+ `GROUP_LDST_MISC: begin
+ dec_ldst = ldst_misc;
+ ldst_addr = ldst_misc;
+
+ dec_snd.r = ldst_misc_off_reg;
+ dec_snd.imm = {4'b0, ldst_misc_off_imm};
+ dec_snd.is_imm = ldst_misc_off_is_imm;
+ end
+
+ `GROUP_ALU: begin
+ snd_is_imm = data_is_imm;
+ snd_ror_if_imm = 1;
+ snd_shift_by_reg_if_reg = data_shift_by_reg_if_reg;
+
+ dec_snd = snd;
+ dec_data = data;
+
+ writeback = data_writeback;
+ update_flags = data_update_flags;
+ restore_spsr = data_restore_spsr;
+
+ undefined = snd_undefined;
+ conditional = data_conditional;
+ end
+
+ `GROUP_LDST_SINGLE: begin
+ snd_is_imm = ldst_single_is_imm;
+ snd_ror_if_imm = 0;
+ snd_shift_by_reg_if_reg = 0;
+
+ dec_snd = snd;
+ dec_ldst = ldst_single;
+ ldst_addr = ldst_single;
+
+ undefined = snd_undefined;
+ end
+
+ `GROUP_LDST_MULT: begin
+ dec_ldst = ldst_multiple;
+ ldst_addr = ldst_multiple;
+ dec_snd.imm = 12'd4;
+
+ restore_spsr = ldst_mult_restore_spsr;
+ end
+
+ `GROUP_CP: begin
+ coproc = 1;
+ writeback = coproc_writeback;
+ update_flags = coproc_update_flags;
+
+ dec_data.op = `ALU_MOV;
+ dec_data.rn = coproc_rd;
+ dec_data.rd = coproc_rd;
+ dec_data.uses_rn = dec_coproc.load;
+ end
+
+ `INSN_MRS: begin
+ dec_data.rd = mrs_rd;
+ dec_data.uses_rn = 0;
+
+ psr = 1;
+ psr_saved = mrs_spsr;
+ writeback = 1;
+ conditional = 1;
+ end
+
+ `GROUP_MSR: begin
+ dec_data.uses_rn = 0;
+
+ snd_is_imm = msr_is_imm;
+ snd_ror_if_imm = 1;
+ snd_shift_by_reg_if_reg = 0;
+
+ psr = 1;
+ dec_snd = snd;
+ psr_write = 1;
+ psr_saved = msr_spsr;
+ conditional = 1;
+ psr_wr_flags = msr_fields.f;
+ psr_wr_control = msr_fields.c;
+ end
+
+ // WONTFIX: <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=9757>
+ //`GROUP_SWP: ;
+
+ `INSN_SWI: begin
+ swi = 1;
+ dec_data.uses_rn = 0;
+ end
+
+ /* No es parte de ARMv4 pero U-Boot lo necesita. esto se
+ * decodifica igual que `mov pc, lr` ya que no tenemos Thumb.
+ */
+ `INSN_BXLR: begin
+ dec_data.op = `ALU_MOV;
+ dec_data.rd = `R15;
+ dec_data.uses_rn = 0;
+
+ dec_snd.r = `R14;
+ dec_snd.is_imm = 0;
+
+ writeback = 1;
+ end
+
+`ifdef VERILATOR
+ // No es parte de ARM del todo, es un hack para soportar gdb
+ `INSN_GDB_SWBREAK: begin
+ bkpt = 1;
+ dec_data.uses_rn = 0;
+ end
+`endif
+
+ default:
+ undefined = 1;
+ endcase
+
+ unique casez(insn `FIELD_OP)
+ // Codificación coincide con ldst
+ `GROUP_MUL: ;
+
+ `GROUP_LDST_SINGLE, `GROUP_LDST_MISC, `GROUP_LDST_MULT, `GROUP_LDST_EX: begin
+ ldst = 1;
+ dec_data = data_ldst;
+ writeback = dec_ldst.writeback || dec_ldst.load || dec_ldst.exclusive;
+ end
+
+ default: ;
+ endcase
+
+ if(undefined) begin
+ execute = 0;
+
+ mul = 1'bx;
+ psr = 1'bx;
+ ldst = 1'bx;
+ branch = 1'bx;
+ coproc = 1'bx;
+ writeback = 1'bx;
+ conditional = 1'bx;
+ update_flags = 1'bx;
+
+ dec_snd = {($bits(dec_snd)){1'bx}};
+ dec_data = {($bits(dec_data)){1'bx}};
+ dec_ldst = {($bits(dec_ldst)){1'bx}};
+ end
+ end
+
+endmodule