From f3b18ead59ae02f95dabbf0a1dea40873a816975 Mon Sep 17 00:00:00 2001 From: Alejandro Soto Date: Sun, 21 Jan 2024 06:23:46 -0600 Subject: rtl: refactor filenames and directory hierarchy --- rtl/cache/cache_mem.sv | 59 +++++++ rtl/cache/cache_monitor.sv | 113 +++++++++++++ rtl/cache/cache_offsets.sv | 91 ++++++++++ rtl/cache/cache_ring.sv | 77 +++++++++ rtl/cache/cache_routing.sv | 147 ++++++++++++++++ rtl/cache/cache_sram.sv | 71 ++++++++ rtl/cache/cache_token.sv | 57 +++++++ rtl/cache/mem.sv | 59 ------- rtl/cache/monitor.sv | 113 ------------- rtl/cache/offsets.sv | 91 ---------- rtl/cache/ring.sv | 77 --------- rtl/cache/routing.sv | 147 ---------------- rtl/cache/sram.sv | 71 -------- rtl/cache/token.sv | 57 ------- rtl/core/alu/add.sv | 45 ----- rtl/core/alu/alu.sv | 139 ---------------- rtl/core/alu/and.sv | 12 -- rtl/core/alu/orr.sv | 12 -- rtl/core/alu/xor.sv | 12 -- rtl/core/arm810.sv | 2 +- rtl/core/control/branch.sv | 30 ---- rtl/core/control/control.sv | 183 -------------------- rtl/core/control/coproc.sv | 32 ---- rtl/core/control/cycles.sv | 148 ----------------- rtl/core/control/data.sv | 117 ------------- rtl/core/control/debug.sv | 25 --- rtl/core/control/exception.sv | 70 -------- rtl/core/control/issue.sv | 80 --------- rtl/core/control/ldst/ldst.sv | 129 -------------- rtl/core/control/ldst/pop.sv | 56 ------- rtl/core/control/ldst/sizes.sv | 46 ----- rtl/core/control/mul_fu.sv | 67 -------- rtl/core/control/select.sv | 80 --------- rtl/core/control/stall.sv | 42 ----- rtl/core/control/status.sv | 81 --------- rtl/core/control/writeback.sv | 128 -------------- rtl/core/core_alu.sv | 139 ++++++++++++++++ rtl/core/core_alu_add.sv | 45 +++++ rtl/core/core_alu_and.sv | 12 ++ rtl/core/core_alu_orr.sv | 12 ++ rtl/core/core_alu_xor.sv | 12 ++ rtl/core/core_control.sv | 183 ++++++++++++++++++++ rtl/core/core_control_branch.sv | 30 ++++ rtl/core/core_control_coproc.sv | 32 ++++ rtl/core/core_control_cycles.sv | 148 +++++++++++++++++ rtl/core/core_control_data.sv | 117 +++++++++++++ rtl/core/core_control_debug.sv | 25 +++ rtl/core/core_control_exception.sv | 70 ++++++++ rtl/core/core_control_issue.sv | 80 +++++++++ rtl/core/core_control_ldst.sv | 129 ++++++++++++++ rtl/core/core_control_ldst_pop.sv | 56 +++++++ rtl/core/core_control_ldst_sizes.sv | 46 +++++ rtl/core/core_control_mul.sv | 67 ++++++++ rtl/core/core_control_psr.sv | 81 +++++++++ rtl/core/core_control_select.sv | 80 +++++++++ rtl/core/core_control_stall.sv | 42 +++++ rtl/core/core_control_writeback.sv | 128 ++++++++++++++ rtl/core/core_cp15.sv | 144 ++++++++++++++++ rtl/core/core_cp15_cache.sv | 15 ++ rtl/core/core_cp15_cache_lockdown.sv | 18 ++ rtl/core/core_cp15_cpuid.sv | 70 ++++++++ rtl/core/core_cp15_cyclecnt.sv | 23 +++ rtl/core/core_cp15_domain.sv | 24 +++ rtl/core/core_cp15_far.sv | 31 ++++ rtl/core/core_cp15_fsr.sv | 43 +++++ rtl/core/core_cp15_syscfg.sv | 68 ++++++++ rtl/core/core_cp15_tlb.sv | 15 ++ rtl/core/core_cp15_tlb_lockdown.sv | 18 ++ rtl/core/core_cp15_ttbr.sv | 45 +++++ rtl/core/core_decode.sv | 195 ++++++++++++++++++++++ rtl/core/core_decode_branch.sv | 18 ++ rtl/core/core_decode_coproc.sv | 24 +++ rtl/core/core_decode_data.sv | 65 ++++++++ rtl/core/core_decode_ldst_addr.sv | 15 ++ rtl/core/core_decode_ldst_exclusive.sv | 27 +++ rtl/core/core_decode_ldst_misc.sv | 36 ++++ rtl/core/core_decode_ldst_multiple.sv | 34 ++++ rtl/core/core_decode_ldst_single.sv | 31 ++++ rtl/core/core_decode_mrs.sv | 15 ++ rtl/core/core_decode_msr.sv | 17 ++ rtl/core/core_decode_mul.sv | 33 ++++ rtl/core/core_decode_mux.sv | 295 +++++++++++++++++++++++++++++++++ rtl/core/core_decode_snd.sv | 75 +++++++++ rtl/core/core_fetch.sv | 74 +++++++++ rtl/core/core_mmu.sv | 140 ++++++++++++++++ rtl/core/core_mmu_arbiter.sv | 132 +++++++++++++++ rtl/core/core_mmu_fault.sv | 83 ++++++++++ rtl/core/core_mmu_pagewalk.sv | 266 +++++++++++++++++++++++++++++ rtl/core/core_mul.sv | 64 +++++++ rtl/core/core_porch.sv | 57 +++++++ rtl/core/core_porch_conds.sv | 47 ++++++ rtl/core/core_prefetch.sv | 84 ++++++++++ rtl/core/core_psr.sv | 172 +++++++++++++++++++ rtl/core/core_reg_file.sv | 51 ++++++ rtl/core/core_reg_map.sv | 30 ++++ rtl/core/core_regs.sv | 69 ++++++++ rtl/core/core_shifter.sv | 42 +++++ rtl/core/cp15/cache_lockdown.sv | 18 -- rtl/core/cp15/cache_ops.sv | 15 -- rtl/core/cp15/cp15.sv | 144 ---------------- rtl/core/cp15/cpuid.sv | 70 -------- rtl/core/cp15/cyclecnt.sv | 23 --- rtl/core/cp15/domain.sv | 24 --- rtl/core/cp15/far.sv | 31 ---- rtl/core/cp15/fsr.sv | 43 ----- rtl/core/cp15/map.sv | 127 -------------- rtl/core/cp15/syscfg.sv | 68 -------- rtl/core/cp15/tlb.sv | 15 -- rtl/core/cp15/tlb_lockdown.sv | 18 -- rtl/core/cp15/ttbr.sv | 45 ----- rtl/core/cp15_map.sv | 127 ++++++++++++++ rtl/core/decode/branch_dec.sv | 18 -- rtl/core/decode/coproc_dec.sv | 24 --- rtl/core/decode/data_dec.sv | 65 -------- rtl/core/decode/decode.sv | 195 ---------------------- rtl/core/decode/isa.sv | 227 ------------------------- rtl/core/decode/ldst/addr.sv | 15 -- rtl/core/decode/ldst/exclusive.sv | 27 --- rtl/core/decode/ldst/misc.sv | 36 ---- rtl/core/decode/ldst/multiple.sv | 34 ---- rtl/core/decode/ldst/single.sv | 31 ---- rtl/core/decode/mrs.sv | 15 -- rtl/core/decode/msr.sv | 17 -- rtl/core/decode/mul_dec.sv | 33 ---- rtl/core/decode/mux.sv | 295 --------------------------------- rtl/core/decode/snd.sv | 75 --------- rtl/core/fetch/fetch.sv | 74 --------- rtl/core/fetch/prefetch.sv | 84 ---------- rtl/core/isa.sv | 227 +++++++++++++++++++++++++ rtl/core/mmu/arbiter.sv | 132 --------------- rtl/core/mmu/fault.sv | 83 ---------- rtl/core/mmu/format.sv | 105 ------------ rtl/core/mmu/mmu.sv | 140 ---------------- rtl/core/mmu/pagewalk.sv | 266 ----------------------------- rtl/core/mmu_format.sv | 105 ++++++++++++ rtl/core/mul.sv | 64 ------- rtl/core/porch/conds.sv | 47 ------ rtl/core/porch/porch.sv | 57 ------- rtl/core/psr.sv | 172 ------------------- rtl/core/regs/file.sv | 51 ------ rtl/core/regs/reg_map.sv | 30 ---- rtl/core/regs/regs.sv | 69 -------- rtl/core/shifter.sv | 42 ----- rtl/perf/link.sv | 181 -------------------- rtl/perf/perf_link.sv | 181 ++++++++++++++++++++ rtl/perf/perf_snoop.sv | 129 ++++++++++++++ rtl/perf/snoop.sv | 129 -------------- rtl/smp/pe.sv | 53 ------ rtl/smp/smp_pe.sv | 53 ++++++ 149 files changed, 5677 insertions(+), 5677 deletions(-) create mode 100644 rtl/cache/cache_mem.sv create mode 100644 rtl/cache/cache_monitor.sv create mode 100644 rtl/cache/cache_offsets.sv create mode 100644 rtl/cache/cache_ring.sv create mode 100644 rtl/cache/cache_routing.sv create mode 100644 rtl/cache/cache_sram.sv create mode 100644 rtl/cache/cache_token.sv delete mode 100644 rtl/cache/mem.sv delete mode 100644 rtl/cache/monitor.sv delete mode 100644 rtl/cache/offsets.sv delete mode 100644 rtl/cache/ring.sv delete mode 100644 rtl/cache/routing.sv delete mode 100644 rtl/cache/sram.sv delete mode 100644 rtl/cache/token.sv delete mode 100644 rtl/core/alu/add.sv delete mode 100644 rtl/core/alu/alu.sv delete mode 100644 rtl/core/alu/and.sv delete mode 100644 rtl/core/alu/orr.sv delete mode 100644 rtl/core/alu/xor.sv delete mode 100644 rtl/core/control/branch.sv delete mode 100644 rtl/core/control/control.sv delete mode 100644 rtl/core/control/coproc.sv delete mode 100644 rtl/core/control/cycles.sv delete mode 100644 rtl/core/control/data.sv delete mode 100644 rtl/core/control/debug.sv delete mode 100644 rtl/core/control/exception.sv delete mode 100644 rtl/core/control/issue.sv delete mode 100644 rtl/core/control/ldst/ldst.sv delete mode 100644 rtl/core/control/ldst/pop.sv delete mode 100644 rtl/core/control/ldst/sizes.sv delete mode 100644 rtl/core/control/mul_fu.sv delete mode 100644 rtl/core/control/select.sv delete mode 100644 rtl/core/control/stall.sv delete mode 100644 rtl/core/control/status.sv delete mode 100644 rtl/core/control/writeback.sv create mode 100644 rtl/core/core_alu.sv create mode 100644 rtl/core/core_alu_add.sv create mode 100644 rtl/core/core_alu_and.sv create mode 100644 rtl/core/core_alu_orr.sv create mode 100644 rtl/core/core_alu_xor.sv create mode 100644 rtl/core/core_control.sv create mode 100644 rtl/core/core_control_branch.sv create mode 100644 rtl/core/core_control_coproc.sv create mode 100644 rtl/core/core_control_cycles.sv create mode 100644 rtl/core/core_control_data.sv create mode 100644 rtl/core/core_control_debug.sv create mode 100644 rtl/core/core_control_exception.sv create mode 100644 rtl/core/core_control_issue.sv create mode 100644 rtl/core/core_control_ldst.sv create mode 100644 rtl/core/core_control_ldst_pop.sv create mode 100644 rtl/core/core_control_ldst_sizes.sv create mode 100644 rtl/core/core_control_mul.sv create mode 100644 rtl/core/core_control_psr.sv create mode 100644 rtl/core/core_control_select.sv create mode 100644 rtl/core/core_control_stall.sv create mode 100644 rtl/core/core_control_writeback.sv create mode 100644 rtl/core/core_cp15.sv create mode 100644 rtl/core/core_cp15_cache.sv create mode 100644 rtl/core/core_cp15_cache_lockdown.sv create mode 100644 rtl/core/core_cp15_cpuid.sv create mode 100644 rtl/core/core_cp15_cyclecnt.sv create mode 100644 rtl/core/core_cp15_domain.sv create mode 100644 rtl/core/core_cp15_far.sv create mode 100644 rtl/core/core_cp15_fsr.sv create mode 100644 rtl/core/core_cp15_syscfg.sv create mode 100644 rtl/core/core_cp15_tlb.sv create mode 100644 rtl/core/core_cp15_tlb_lockdown.sv create mode 100644 rtl/core/core_cp15_ttbr.sv create mode 100644 rtl/core/core_decode.sv create mode 100644 rtl/core/core_decode_branch.sv create mode 100644 rtl/core/core_decode_coproc.sv create mode 100644 rtl/core/core_decode_data.sv create mode 100644 rtl/core/core_decode_ldst_addr.sv create mode 100644 rtl/core/core_decode_ldst_exclusive.sv create mode 100644 rtl/core/core_decode_ldst_misc.sv create mode 100644 rtl/core/core_decode_ldst_multiple.sv create mode 100644 rtl/core/core_decode_ldst_single.sv create mode 100644 rtl/core/core_decode_mrs.sv create mode 100644 rtl/core/core_decode_msr.sv create mode 100644 rtl/core/core_decode_mul.sv create mode 100644 rtl/core/core_decode_mux.sv create mode 100644 rtl/core/core_decode_snd.sv create mode 100644 rtl/core/core_fetch.sv create mode 100644 rtl/core/core_mmu.sv create mode 100644 rtl/core/core_mmu_arbiter.sv create mode 100644 rtl/core/core_mmu_fault.sv create mode 100644 rtl/core/core_mmu_pagewalk.sv create mode 100644 rtl/core/core_mul.sv create mode 100644 rtl/core/core_porch.sv create mode 100644 rtl/core/core_porch_conds.sv create mode 100644 rtl/core/core_prefetch.sv create mode 100644 rtl/core/core_psr.sv create mode 100644 rtl/core/core_reg_file.sv create mode 100644 rtl/core/core_reg_map.sv create mode 100644 rtl/core/core_regs.sv create mode 100644 rtl/core/core_shifter.sv delete mode 100644 rtl/core/cp15/cache_lockdown.sv delete mode 100644 rtl/core/cp15/cache_ops.sv delete mode 100644 rtl/core/cp15/cp15.sv delete mode 100644 rtl/core/cp15/cpuid.sv delete mode 100644 rtl/core/cp15/cyclecnt.sv delete mode 100644 rtl/core/cp15/domain.sv delete mode 100644 rtl/core/cp15/far.sv delete mode 100644 rtl/core/cp15/fsr.sv delete mode 100644 rtl/core/cp15/map.sv delete mode 100644 rtl/core/cp15/syscfg.sv delete mode 100644 rtl/core/cp15/tlb.sv delete mode 100644 rtl/core/cp15/tlb_lockdown.sv delete mode 100644 rtl/core/cp15/ttbr.sv create mode 100644 rtl/core/cp15_map.sv delete mode 100644 rtl/core/decode/branch_dec.sv delete mode 100644 rtl/core/decode/coproc_dec.sv delete mode 100644 rtl/core/decode/data_dec.sv delete mode 100644 rtl/core/decode/decode.sv delete mode 100644 rtl/core/decode/isa.sv delete mode 100644 rtl/core/decode/ldst/addr.sv delete mode 100644 rtl/core/decode/ldst/exclusive.sv delete mode 100644 rtl/core/decode/ldst/misc.sv delete mode 100644 rtl/core/decode/ldst/multiple.sv delete mode 100644 rtl/core/decode/ldst/single.sv delete mode 100644 rtl/core/decode/mrs.sv delete mode 100644 rtl/core/decode/msr.sv delete mode 100644 rtl/core/decode/mul_dec.sv delete mode 100644 rtl/core/decode/mux.sv delete mode 100644 rtl/core/decode/snd.sv delete mode 100644 rtl/core/fetch/fetch.sv delete mode 100644 rtl/core/fetch/prefetch.sv create mode 100644 rtl/core/isa.sv delete mode 100644 rtl/core/mmu/arbiter.sv delete mode 100644 rtl/core/mmu/fault.sv delete mode 100644 rtl/core/mmu/format.sv delete mode 100644 rtl/core/mmu/mmu.sv delete mode 100644 rtl/core/mmu/pagewalk.sv create mode 100644 rtl/core/mmu_format.sv delete mode 100644 rtl/core/mul.sv delete mode 100644 rtl/core/porch/conds.sv delete mode 100644 rtl/core/porch/porch.sv delete mode 100644 rtl/core/psr.sv delete mode 100644 rtl/core/regs/file.sv delete mode 100644 rtl/core/regs/reg_map.sv delete mode 100644 rtl/core/regs/regs.sv delete mode 100644 rtl/core/shifter.sv delete mode 100644 rtl/perf/link.sv create mode 100644 rtl/perf/perf_link.sv create mode 100644 rtl/perf/perf_snoop.sv delete mode 100644 rtl/perf/snoop.sv delete mode 100644 rtl/smp/pe.sv create mode 100644 rtl/smp/smp_pe.sv (limited to 'rtl') diff --git a/rtl/cache/cache_mem.sv b/rtl/cache/cache_mem.sv new file mode 100644 index 0000000..a575d0d --- /dev/null +++ b/rtl/cache/cache_mem.sv @@ -0,0 +1,59 @@ +`include "cache/defs.sv" + +module cache_mem +( + input logic clk, + rst_n, + + input addr_tag core_tag, + + // Señales para la SRAM + input addr_tag tag_rd, // valor de la tag de esa línea + input line data_rd, // datos de la línea + + input addr_index index_wr, + + input logic mem_waitrequest, + output word mem_address, + output logic mem_read, + mem_write, + output line mem_writedata, + + input logic mem_begin, + writeback, + output logic mem_end, + mem_read_end, + mem_wait, + output addr_tag mem_tag, + output addr_index mem_index +); + + assign mem_end = (mem_read || mem_write) && !mem_waitrequest; + assign mem_wait = (mem_read || mem_write) && mem_waitrequest; + assign mem_address = {`IO_CACHED, mem_tag, mem_index, 4'b0000}; + assign mem_read_end = mem_read && !mem_waitrequest; + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + mem_read <= 0; + mem_write <= 0; + end else begin + if (mem_end) begin + mem_read <= 0; + mem_write <= 0; + end + + if (mem_begin) begin + mem_read <= !writeback; + mem_write <= writeback; + end + end + + always_ff @(posedge clk) + if (mem_begin) begin + mem_tag <= writeback ? tag_rd : core_tag; + mem_index <= index_wr; + mem_writedata <= data_rd; + end + +endmodule diff --git a/rtl/cache/cache_monitor.sv b/rtl/cache/cache_monitor.sv new file mode 100644 index 0000000..380019e --- /dev/null +++ b/rtl/cache/cache_monitor.sv @@ -0,0 +1,113 @@ +`include "cache/defs.sv" + +module cache_monitor +( + input logic clk, + rst_n, + + input addr_tag core_tag, + input addr_index core_index, + input addr_offset core_offset, // Alguno de los 4 cores + input logic core_lock, + input word core_writedata, + output logic[1:0] core_response, + + input line data_rd, + + input logic monitor_acquire, + monitor_fail, + monitor_release, + output line monitor_update, + output logic monitor_commit +); + + // Este módulo provee capacidad para spin_locks (básicamente mutexes) para + // proteger una sección de código a través de spin lock/unlock. + // Esto básicamente es la implemenntación de las instrucciones de ARM + // ldrex, strexeq, que originalmente no son parte ARMv4, esto implica + // que este quad-core es un frankenstein entre ARMv4 y alguna versión + // posterior que sí implementa esas instrucciones. + + + line monitor_rd, monitor_wr; + word update_3, update_2, update_1, update_0; + logic dirty, done, hit, known; + addr_tag tag; + addr_index index; + + logic[3:0] mask, mask_clear, core_ex_mask; + + assign monitor_commit = !core_lock || (hit && known && done); + assign monitor_update = {update_3, update_2, update_1, update_0}; + + /* Avalon p. 15: + * - 00: OKAY - Successful response for a transaction. + * - 10: SLVERR - Error from an endpoint agent. Indicates an unsuccessful transaction. + */ + assign core_response = {monitor_fail, 1'b0}; + + assign hit = tag == core_tag && index == core_index; + assign done = monitor_rd == data_rd && mask_clear == 4'b0000; + assign known = mask[core_offset]; + assign mask_clear = mask & ~core_ex_mask; + + always_comb begin + {update_3, update_2, update_1, update_0} = monitor_wr; + + unique case (core_offset) + 2'b00: begin + update_0 = core_writedata; + core_ex_mask = 4'b0001; + end + + 2'b01: begin + update_1 = core_writedata; + core_ex_mask = 4'b0010; + end + + 2'b10: begin + update_2 = core_writedata; + core_ex_mask = 4'b0100; + end + + 2'b11: begin + update_3 = core_writedata; + core_ex_mask = 4'b1000; + end + endcase + end + + always @(posedge clk or negedge rst_n) + if (!rst_n) begin + mask <= 4'b0000; + dirty <= 0; + end else begin + // ldrex + if (monitor_acquire) begin + mask <= hit && !known && !dirty ? mask | core_ex_mask : core_ex_mask; + dirty <= 0; + end + + // strexeq + if (monitor_release) begin + mask <= hit && known ? mask_clear : 4'b0000; + dirty <= hit && known; + end + end + + always_ff @(posedge clk) begin + if (monitor_acquire) begin + tag <= core_tag; + index <= core_index; + + if (!hit || known || dirty || mask == 4'b0000) begin + monitor_rd <= data_rd; + monitor_wr <= data_rd; + end + end + + if (monitor_release) + monitor_wr <= monitor_update; + end + +endmodule diff --git a/rtl/cache/cache_offsets.sv b/rtl/cache/cache_offsets.sv new file mode 100644 index 0000000..7769394 --- /dev/null +++ b/rtl/cache/cache_offsets.sv @@ -0,0 +1,91 @@ +`include "cache/defs.sv" + +module cache_offsets +( + input addr_offset core_offset, // El offset es un input pero no + // un output porque se mapea + input word_be core_byteenable, + input word core_writedata, + input line core_readdata_line, + data_rd, + + output line core_data_wr, + core_writedata_line, + output word core_readdata, // Readdata pasa de ser una line + // en el input a una word por el + // offset + output line_be core_byteenable_line +); + + // Este módulo sirve para simplificar offsets, para que sean transparentes + // para la cache. El caché nunca ve la parte de offset que hay en las + // direccciones. + + // El core trabaja en words. El caché en lines, esto es el puente entre + // ambos tipos de datos. + + line line_mask; + + // El byteenable (be) se utiliza cuando se quiere leer o escribir en cache + // un solo byte, en lugar de una word entera + word be_extend, mask3, mask2, mask1, mask0; + word_be be3, be2, be1, be0; + + // Concatena la misma word 4 veces. + assign core_writedata_line = {4{core_writedata}}; + + // Se prepara la mask de byte enable para cada word. + assign core_byteenable_line = {be3, be2, be1, be0}; + + // Concatenar para extender a una word ([31:0]). El valor de be determina + // a cuál word se va a extender. + assign be_extend = {{8{core_byteenable[3]}}, {8{core_byteenable[2]}}, + {8{core_byteenable[1]}}, {8{core_byteenable[0]}}}; + + // Máscara para toda la línea + assign line_mask = {mask3, mask2, mask1, mask0}; + + // Se preserva lo que no hay que cambiar (data_rd & ~line_mask) y se aplica + // la máscara a lo que sí hay cambiar (core_writedata_line & line_mask). + assign core_data_wr = (core_writedata_line & line_mask) | (data_rd & ~line_mask); + + always_comb begin + mask3 = 0; + mask2 = 0; + mask1 = 0; + mask0 = 0; + + be3 = 0; + be2 = 0; + be1 = 0; + be0 = 0; + + // Elegir la word que se va a retornar según el valor de offset + unique case (core_offset) + 2'b00: begin + be0 = core_byteenable; + mask0 = be_extend; + core_readdata = core_readdata_line[31:0]; + end + + 2'b01: begin + be1 = core_byteenable; + mask1 = be_extend; + core_readdata = core_readdata_line[63:32]; + end + + 2'b10: begin + be2 = core_byteenable; + mask2 = be_extend; + core_readdata = core_readdata_line[95:64]; + end + + 2'b11: begin + be3 = core_byteenable; + mask3 = be_extend; + core_readdata = core_readdata_line[127:96]; + end + endcase + end + +endmodule diff --git a/rtl/cache/cache_ring.sv b/rtl/cache/cache_ring.sv new file mode 100644 index 0000000..d934fb7 --- /dev/null +++ b/rtl/cache/cache_ring.sv @@ -0,0 +1,77 @@ +`include "cache/defs.sv" + +module cache_ring +( + input logic clk, + rst_n, + + input addr_tag core_tag, + input addr_index core_index, + + input ring_req in_data, // lo que se recibe + input logic in_data_valid, // este caché está recibiendo + in_data_ready, + + input logic out_data_ready, // este caché está listo para enviar + output ring_req out_data, // lo que se envía + output logic out_data_valid, // este caché está enviando datos + + input line data_rd, // datos de la línea + + input logic send, + send_read, + send_inval, + set_reply, + output logic out_stall, + in_hold_valid, + last_hop, + output ring_req in_hold +); + + // in_hold: el paquete actual + ring_req send_data, fwd_data, stall_data, out_data_next; + + assign last_hop = in_hold.ttl == `TTL_END; //Indica si es el último salto + + assign out_data = out_stall ? stall_data : out_data_next; + assign out_data_next = send ? send_data : fwd_data; + assign out_data_valid = out_stall || send || (in_hold_valid && !last_hop && in_data_ready); + + assign send_data.tag = core_tag; + assign send_data.ttl = `TTL_MAX; // Acá se inicializa el valor máximo de TTL + assign send_data.data = fwd_data.data; // Esto evita muchos muxes + assign send_data.read = send_read; + assign send_data.index = core_index; + assign send_data.inval = send_inval; + assign send_data.reply = 0; + + always_comb begin + fwd_data = in_hold; + fwd_data.ttl = in_hold.ttl - 2'b1; + + if (set_reply) begin + fwd_data.data = data_rd; + fwd_data.reply = 1; + end + end + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + in_hold_valid <= 0; + out_stall <= 0; + end else begin + if (in_data_ready) + in_hold_valid <= in_data_valid; + + out_stall <= out_data_valid && !out_data_ready; + end + + always_ff @(posedge clk) begin + if (in_data_ready) + in_hold <= in_data; + + if (!out_stall) + stall_data <= out_data_next; + end + +endmodule diff --git a/rtl/cache/cache_routing.sv b/rtl/cache/cache_routing.sv new file mode 100644 index 0000000..a0c4347 --- /dev/null +++ b/rtl/cache/cache_routing.sv @@ -0,0 +1,147 @@ +`include "cache/defs.sv" +`include "config.sv" + +module cache_routing +( + input logic clk, + rst_n, + + input ptr core_address, + input logic core_read, + core_write, + input line core_writedata_line, + input line_be core_byteenable_line, + output logic core_waitrequest, + output line core_readdata_line, + + output addr_tag core_tag, + output addr_index core_index, + output addr_offset core_offset, + + input line data_rd, + input logic cache_core_waitrequest, + output logic cache_core_read, + cache_core_write, + + input word cache_mem_address, + input logic cache_mem_read, + cache_mem_write, + input line cache_mem_writedata, + output logic cache_mem_waitrequest, + + input logic mem_waitrequest, + input line mem_readdata, + output word mem_address, + output logic mem_read, + mem_write, + output line mem_writedata, + output line_be mem_byteenable +); + + /* Módulo para enrutar las operaciones a cache o memoria + * Esto porque hay escrituras que definitivamente no pueden quedar en cache + * como el caso de periféricos, para los cuales si se guarda "su valor" en + * cache y no en memoria se harían lecturas incorrectas + */ + + word core_address_line; + logic cached, cache_mem, transition; + addr_io_region io; + + enum int unsigned + { + IDLE, + CACHE, + BYPASS + } state; + + //Arbitrar el bus del lado de la cache + + /* Se sabe si el address es cache o no evaluando los bits de IO. + * Esto es posible porque se cumple lo siguiente: + * - La memoria tiene un tamaño que es una potencia de 2 + * - Sus direcciones inician en 0 + * Entonces si los bits de IO son distintos de 0, se sabe que no es + * una dirección cached + */ + assign cached = io == `IO_CACHED && `CONFIG_CACHE; + // Se afirma si cache quiere hacer un read o write de memoria + assign cache_mem = cache_mem_read || cache_mem_write; + + // Acá se divide el core_address para analizarse por separado + assign {io, core_tag, core_index, core_offset} = core_address; + assign core_address_line = {io, core_tag, core_index, 4'b0000}; + // Si está cached se asigna a lectura de cache, sino a lectura de memoria + assign core_readdata_line = cached ? data_rd : mem_readdata; + + // Se afirma si el core quiere leer/escribir a cache y efectivamente es una + // dirección de cache + assign cache_core_read = core_read && cached; + assign cache_core_write = core_write && cached; + + // Máquina de estados: + // IDLE/CACHE/BYPASS + // Bypass: el request evita pasar por caché, para que no quede escrito el + // el dato. Esto sirve para periféricos, por ejemplo. + // Cache: el request sí pasa por caché, esto sucede para todo lo que va + // para RAM. + always_comb begin + transition = 0; + core_waitrequest = cache_core_waitrequest; + // Desde el punto de vista de cache, mem le hace waitreq a cache + cache_mem_waitrequest = 1; + + unique case (state) + IDLE: + /* Transition se afirma si cache quiere hacer un read o write de + * memoria, o si el address no es cache y el core quiere leer + * o escribir a cache + */ + transition = cache_mem || (!cached && (core_read || core_write)); + + CACHE: + // Cache le hace waitreq a memoria + cache_mem_waitrequest = mem_waitrequest; + + BYPASS: + // Se le hace waitreq al core si la memoria también lo hace + core_waitrequest = mem_waitrequest; + endcase + end + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + state <= IDLE; + mem_read <= 0; + mem_write <= 0; + end else unique case (state) + IDLE: + if (transition) begin + // Si cache quiere hacer una operación con memoria, se pasa + // a CACHE, sino hay que hacer BYPASS. Si la operación + // no es directo a memoria, se hace bypasss porque esto + // implica que el dato no tiene que quedar cacheado. (Talvez + // es algo de un periférico, etc.) + state <= cache_mem ? CACHE : BYPASS; + mem_read <= cache_mem ? cache_mem_read : core_read; + mem_write <= cache_mem ? cache_mem_write : core_write; + end + + CACHE, BYPASS: + if (!mem_waitrequest) begin + state <= IDLE; + mem_read <= 0; + mem_write <= 0; + end + endcase + + always_ff @(posedge clk) + if (transition) begin + // Si cache no quiere hacer una operación con memoria, se asignan + // las señales del core + mem_address <= cache_mem ? cache_mem_address : core_address_line; + mem_writedata <= cache_mem ? cache_mem_writedata : core_writedata_line; + mem_byteenable <= cache_mem ? 16'hffff : core_byteenable_line; + end + +endmodule diff --git a/rtl/cache/cache_sram.sv b/rtl/cache/cache_sram.sv new file mode 100644 index 0000000..d63cdad --- /dev/null +++ b/rtl/cache/cache_sram.sv @@ -0,0 +1,71 @@ +`include "cache/defs.sv" + +module cache_sram +( + input logic clk, + rst_n, + + input addr_index index_rd, + index_wr, + input logic write_data, + write_state, + input addr_tag tag_wr, + input line data_wr, + input line_state state_wr, + + output addr_tag tag_rd, + output line data_rd, + output line_state state_rd +); + + // Existe un mito que habla de true dual-ports con byte-enables, + // probablemente no sea real: + // https://www.intel.com/content/www/us/en/docs/programmable/683082/21-3/ram-with-byte-enable-signals.html + + // Es una cache one way: cada índice mapea a cada línea de cache + // (directamente mapeada) + + // Define la cantidad de líneas de cache + // Cantidad de bits en addr_index = 12, entonces se le hace left shift 12 + // espacios a 1. Osea, 4096 líneas de cache. + // Tenemos 4kilo-líneas de caché. Cada línea es de 128bits, osea tenemos una + // caché de 64KBi. + localparam DEPTH = 1 << $bits(addr_index); + + // Estas tres secciones constituyen al caché. + // data_file: Donde se guarda la información cacheada. + // tag_file: Se guardan los tags de las líneas de caché. + // state_file: Se guarda el estado de cada línea de caché. (Acá están todos + // los estados de MESI) + line data_file[DEPTH] /*verilator public*/; + addr_tag tag_file[DEPTH] /*verilator public*/; + line_state state_file[DEPTH] /*verilator public*/; + + // 3 funciones principales: + // 1. Si se necesita escribir un dato: escribe en los tag y data files en + // la posición del index de escritura + // 2. Si se necesita escribir un estado: escribe en el state file en la + // posición del index de escritura + // 3. Cada ciclo retorna siempre lo que esté en todos los files en la + // posición de index de lectura + always_ff @(posedge clk) begin + if (write_data) begin + tag_file[index_wr] <= tag_wr; + data_file[index_wr] <= data_wr; + end + + if (write_state) + state_file[index_wr] <= state_wr; + + tag_rd <= tag_file[index_rd]; + data_rd <= data_file[index_rd]; + state_rd <= state_file[index_rd]; + end + + // Se inicializan todas las líneas del state file como INVALID + //FIXME: rst_n para state_file? + initial + for (int i = 0; i < DEPTH; ++i) + state_file[i] = INVALID; + +endmodule diff --git a/rtl/cache/cache_token.sv b/rtl/cache/cache_token.sv new file mode 100644 index 0000000..cb3e59d --- /dev/null +++ b/rtl/cache/cache_token.sv @@ -0,0 +1,57 @@ +`include "cache/defs.sv" + +module cache_token +#(parameter TOKEN_AT_RESET=0) +( + input logic clk, + rst_n, + + input addr_tag core_tag, + input addr_index core_index, + + input ring_token in_token, // input del token + input logic in_token_valid, // se está recibiendo el token + + output ring_token out_token, // output del token + output logic out_token_valid, // se está enviando el token + + input logic send, + lock_line, + unlock_line, + output logic locked, + may_send +); + + logic may_send_if_token_held; + + // Solo se puede iniciar un request si se tiene el token y el token es + // válido + assign may_send = may_send_if_token_held && in_token_valid; + assign may_send_if_token_held + = (!in_token.e2.valid || in_token.e2.index != core_index || in_token.e2.tag != core_tag) + && (!in_token.e1.valid || in_token.e1.index != core_index || in_token.e1.tag != core_tag) + && (!in_token.e0.valid || in_token.e0.index != core_index || in_token.e0.tag != core_tag); + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + out_token <= {($bits(out_token)){1'b0}}; + out_token_valid <= TOKEN_AT_RESET; + + locked <= 0; + end else begin + out_token.e0.tag <= core_tag; + out_token.e0.index <= core_index; + out_token.e0.valid <= may_send_if_token_held && (send || locked) && !unlock_line; + + out_token.e2 <= in_token.e1; + out_token.e1 <= in_token.e0; + out_token_valid <= in_token_valid; + + if (lock_line) + locked <= 1; + + if (unlock_line) + locked <= 0; + end + +endmodule diff --git a/rtl/cache/mem.sv b/rtl/cache/mem.sv deleted file mode 100644 index a575d0d..0000000 --- a/rtl/cache/mem.sv +++ /dev/null @@ -1,59 +0,0 @@ -`include "cache/defs.sv" - -module cache_mem -( - input logic clk, - rst_n, - - input addr_tag core_tag, - - // Señales para la SRAM - input addr_tag tag_rd, // valor de la tag de esa línea - input line data_rd, // datos de la línea - - input addr_index index_wr, - - input logic mem_waitrequest, - output word mem_address, - output logic mem_read, - mem_write, - output line mem_writedata, - - input logic mem_begin, - writeback, - output logic mem_end, - mem_read_end, - mem_wait, - output addr_tag mem_tag, - output addr_index mem_index -); - - assign mem_end = (mem_read || mem_write) && !mem_waitrequest; - assign mem_wait = (mem_read || mem_write) && mem_waitrequest; - assign mem_address = {`IO_CACHED, mem_tag, mem_index, 4'b0000}; - assign mem_read_end = mem_read && !mem_waitrequest; - - always_ff @(posedge clk or negedge rst_n) - if (!rst_n) begin - mem_read <= 0; - mem_write <= 0; - end else begin - if (mem_end) begin - mem_read <= 0; - mem_write <= 0; - end - - if (mem_begin) begin - mem_read <= !writeback; - mem_write <= writeback; - end - end - - always_ff @(posedge clk) - if (mem_begin) begin - mem_tag <= writeback ? tag_rd : core_tag; - mem_index <= index_wr; - mem_writedata <= data_rd; - end - -endmodule diff --git a/rtl/cache/monitor.sv b/rtl/cache/monitor.sv deleted file mode 100644 index 380019e..0000000 --- a/rtl/cache/monitor.sv +++ /dev/null @@ -1,113 +0,0 @@ -`include "cache/defs.sv" - -module cache_monitor -( - input logic clk, - rst_n, - - input addr_tag core_tag, - input addr_index core_index, - input addr_offset core_offset, // Alguno de los 4 cores - input logic core_lock, - input word core_writedata, - output logic[1:0] core_response, - - input line data_rd, - - input logic monitor_acquire, - monitor_fail, - monitor_release, - output line monitor_update, - output logic monitor_commit -); - - // Este módulo provee capacidad para spin_locks (básicamente mutexes) para - // proteger una sección de código a través de spin lock/unlock. - // Esto básicamente es la implemenntación de las instrucciones de ARM - // ldrex, strexeq, que originalmente no son parte ARMv4, esto implica - // que este quad-core es un frankenstein entre ARMv4 y alguna versión - // posterior que sí implementa esas instrucciones. - - - line monitor_rd, monitor_wr; - word update_3, update_2, update_1, update_0; - logic dirty, done, hit, known; - addr_tag tag; - addr_index index; - - logic[3:0] mask, mask_clear, core_ex_mask; - - assign monitor_commit = !core_lock || (hit && known && done); - assign monitor_update = {update_3, update_2, update_1, update_0}; - - /* Avalon p. 15: - * - 00: OKAY - Successful response for a transaction. - * - 10: SLVERR - Error from an endpoint agent. Indicates an unsuccessful transaction. - */ - assign core_response = {monitor_fail, 1'b0}; - - assign hit = tag == core_tag && index == core_index; - assign done = monitor_rd == data_rd && mask_clear == 4'b0000; - assign known = mask[core_offset]; - assign mask_clear = mask & ~core_ex_mask; - - always_comb begin - {update_3, update_2, update_1, update_0} = monitor_wr; - - unique case (core_offset) - 2'b00: begin - update_0 = core_writedata; - core_ex_mask = 4'b0001; - end - - 2'b01: begin - update_1 = core_writedata; - core_ex_mask = 4'b0010; - end - - 2'b10: begin - update_2 = core_writedata; - core_ex_mask = 4'b0100; - end - - 2'b11: begin - update_3 = core_writedata; - core_ex_mask = 4'b1000; - end - endcase - end - - always @(posedge clk or negedge rst_n) - if (!rst_n) begin - mask <= 4'b0000; - dirty <= 0; - end else begin - // ldrex - if (monitor_acquire) begin - mask <= hit && !known && !dirty ? mask | core_ex_mask : core_ex_mask; - dirty <= 0; - end - - // strexeq - if (monitor_release) begin - mask <= hit && known ? mask_clear : 4'b0000; - dirty <= hit && known; - end - end - - always_ff @(posedge clk) begin - if (monitor_acquire) begin - tag <= core_tag; - index <= core_index; - - if (!hit || known || dirty || mask == 4'b0000) begin - monitor_rd <= data_rd; - monitor_wr <= data_rd; - end - end - - if (monitor_release) - monitor_wr <= monitor_update; - end - -endmodule diff --git a/rtl/cache/offsets.sv b/rtl/cache/offsets.sv deleted file mode 100644 index 7769394..0000000 --- a/rtl/cache/offsets.sv +++ /dev/null @@ -1,91 +0,0 @@ -`include "cache/defs.sv" - -module cache_offsets -( - input addr_offset core_offset, // El offset es un input pero no - // un output porque se mapea - input word_be core_byteenable, - input word core_writedata, - input line core_readdata_line, - data_rd, - - output line core_data_wr, - core_writedata_line, - output word core_readdata, // Readdata pasa de ser una line - // en el input a una word por el - // offset - output line_be core_byteenable_line -); - - // Este módulo sirve para simplificar offsets, para que sean transparentes - // para la cache. El caché nunca ve la parte de offset que hay en las - // direccciones. - - // El core trabaja en words. El caché en lines, esto es el puente entre - // ambos tipos de datos. - - line line_mask; - - // El byteenable (be) se utiliza cuando se quiere leer o escribir en cache - // un solo byte, en lugar de una word entera - word be_extend, mask3, mask2, mask1, mask0; - word_be be3, be2, be1, be0; - - // Concatena la misma word 4 veces. - assign core_writedata_line = {4{core_writedata}}; - - // Se prepara la mask de byte enable para cada word. - assign core_byteenable_line = {be3, be2, be1, be0}; - - // Concatenar para extender a una word ([31:0]). El valor de be determina - // a cuál word se va a extender. - assign be_extend = {{8{core_byteenable[3]}}, {8{core_byteenable[2]}}, - {8{core_byteenable[1]}}, {8{core_byteenable[0]}}}; - - // Máscara para toda la línea - assign line_mask = {mask3, mask2, mask1, mask0}; - - // Se preserva lo que no hay que cambiar (data_rd & ~line_mask) y se aplica - // la máscara a lo que sí hay cambiar (core_writedata_line & line_mask). - assign core_data_wr = (core_writedata_line & line_mask) | (data_rd & ~line_mask); - - always_comb begin - mask3 = 0; - mask2 = 0; - mask1 = 0; - mask0 = 0; - - be3 = 0; - be2 = 0; - be1 = 0; - be0 = 0; - - // Elegir la word que se va a retornar según el valor de offset - unique case (core_offset) - 2'b00: begin - be0 = core_byteenable; - mask0 = be_extend; - core_readdata = core_readdata_line[31:0]; - end - - 2'b01: begin - be1 = core_byteenable; - mask1 = be_extend; - core_readdata = core_readdata_line[63:32]; - end - - 2'b10: begin - be2 = core_byteenable; - mask2 = be_extend; - core_readdata = core_readdata_line[95:64]; - end - - 2'b11: begin - be3 = core_byteenable; - mask3 = be_extend; - core_readdata = core_readdata_line[127:96]; - end - endcase - end - -endmodule diff --git a/rtl/cache/ring.sv b/rtl/cache/ring.sv deleted file mode 100644 index d934fb7..0000000 --- a/rtl/cache/ring.sv +++ /dev/null @@ -1,77 +0,0 @@ -`include "cache/defs.sv" - -module cache_ring -( - input logic clk, - rst_n, - - input addr_tag core_tag, - input addr_index core_index, - - input ring_req in_data, // lo que se recibe - input logic in_data_valid, // este caché está recibiendo - in_data_ready, - - input logic out_data_ready, // este caché está listo para enviar - output ring_req out_data, // lo que se envía - output logic out_data_valid, // este caché está enviando datos - - input line data_rd, // datos de la línea - - input logic send, - send_read, - send_inval, - set_reply, - output logic out_stall, - in_hold_valid, - last_hop, - output ring_req in_hold -); - - // in_hold: el paquete actual - ring_req send_data, fwd_data, stall_data, out_data_next; - - assign last_hop = in_hold.ttl == `TTL_END; //Indica si es el último salto - - assign out_data = out_stall ? stall_data : out_data_next; - assign out_data_next = send ? send_data : fwd_data; - assign out_data_valid = out_stall || send || (in_hold_valid && !last_hop && in_data_ready); - - assign send_data.tag = core_tag; - assign send_data.ttl = `TTL_MAX; // Acá se inicializa el valor máximo de TTL - assign send_data.data = fwd_data.data; // Esto evita muchos muxes - assign send_data.read = send_read; - assign send_data.index = core_index; - assign send_data.inval = send_inval; - assign send_data.reply = 0; - - always_comb begin - fwd_data = in_hold; - fwd_data.ttl = in_hold.ttl - 2'b1; - - if (set_reply) begin - fwd_data.data = data_rd; - fwd_data.reply = 1; - end - end - - always_ff @(posedge clk or negedge rst_n) - if (!rst_n) begin - in_hold_valid <= 0; - out_stall <= 0; - end else begin - if (in_data_ready) - in_hold_valid <= in_data_valid; - - out_stall <= out_data_valid && !out_data_ready; - end - - always_ff @(posedge clk) begin - if (in_data_ready) - in_hold <= in_data; - - if (!out_stall) - stall_data <= out_data_next; - end - -endmodule diff --git a/rtl/cache/routing.sv b/rtl/cache/routing.sv deleted file mode 100644 index a0c4347..0000000 --- a/rtl/cache/routing.sv +++ /dev/null @@ -1,147 +0,0 @@ -`include "cache/defs.sv" -`include "config.sv" - -module cache_routing -( - input logic clk, - rst_n, - - input ptr core_address, - input logic core_read, - core_write, - input line core_writedata_line, - input line_be core_byteenable_line, - output logic core_waitrequest, - output line core_readdata_line, - - output addr_tag core_tag, - output addr_index core_index, - output addr_offset core_offset, - - input line data_rd, - input logic cache_core_waitrequest, - output logic cache_core_read, - cache_core_write, - - input word cache_mem_address, - input logic cache_mem_read, - cache_mem_write, - input line cache_mem_writedata, - output logic cache_mem_waitrequest, - - input logic mem_waitrequest, - input line mem_readdata, - output word mem_address, - output logic mem_read, - mem_write, - output line mem_writedata, - output line_be mem_byteenable -); - - /* Módulo para enrutar las operaciones a cache o memoria - * Esto porque hay escrituras que definitivamente no pueden quedar en cache - * como el caso de periféricos, para los cuales si se guarda "su valor" en - * cache y no en memoria se harían lecturas incorrectas - */ - - word core_address_line; - logic cached, cache_mem, transition; - addr_io_region io; - - enum int unsigned - { - IDLE, - CACHE, - BYPASS - } state; - - //Arbitrar el bus del lado de la cache - - /* Se sabe si el address es cache o no evaluando los bits de IO. - * Esto es posible porque se cumple lo siguiente: - * - La memoria tiene un tamaño que es una potencia de 2 - * - Sus direcciones inician en 0 - * Entonces si los bits de IO son distintos de 0, se sabe que no es - * una dirección cached - */ - assign cached = io == `IO_CACHED && `CONFIG_CACHE; - // Se afirma si cache quiere hacer un read o write de memoria - assign cache_mem = cache_mem_read || cache_mem_write; - - // Acá se divide el core_address para analizarse por separado - assign {io, core_tag, core_index, core_offset} = core_address; - assign core_address_line = {io, core_tag, core_index, 4'b0000}; - // Si está cached se asigna a lectura de cache, sino a lectura de memoria - assign core_readdata_line = cached ? data_rd : mem_readdata; - - // Se afirma si el core quiere leer/escribir a cache y efectivamente es una - // dirección de cache - assign cache_core_read = core_read && cached; - assign cache_core_write = core_write && cached; - - // Máquina de estados: - // IDLE/CACHE/BYPASS - // Bypass: el request evita pasar por caché, para que no quede escrito el - // el dato. Esto sirve para periféricos, por ejemplo. - // Cache: el request sí pasa por caché, esto sucede para todo lo que va - // para RAM. - always_comb begin - transition = 0; - core_waitrequest = cache_core_waitrequest; - // Desde el punto de vista de cache, mem le hace waitreq a cache - cache_mem_waitrequest = 1; - - unique case (state) - IDLE: - /* Transition se afirma si cache quiere hacer un read o write de - * memoria, o si el address no es cache y el core quiere leer - * o escribir a cache - */ - transition = cache_mem || (!cached && (core_read || core_write)); - - CACHE: - // Cache le hace waitreq a memoria - cache_mem_waitrequest = mem_waitrequest; - - BYPASS: - // Se le hace waitreq al core si la memoria también lo hace - core_waitrequest = mem_waitrequest; - endcase - end - - always_ff @(posedge clk or negedge rst_n) - if (!rst_n) begin - state <= IDLE; - mem_read <= 0; - mem_write <= 0; - end else unique case (state) - IDLE: - if (transition) begin - // Si cache quiere hacer una operación con memoria, se pasa - // a CACHE, sino hay que hacer BYPASS. Si la operación - // no es directo a memoria, se hace bypasss porque esto - // implica que el dato no tiene que quedar cacheado. (Talvez - // es algo de un periférico, etc.) - state <= cache_mem ? CACHE : BYPASS; - mem_read <= cache_mem ? cache_mem_read : core_read; - mem_write <= cache_mem ? cache_mem_write : core_write; - end - - CACHE, BYPASS: - if (!mem_waitrequest) begin - state <= IDLE; - mem_read <= 0; - mem_write <= 0; - end - endcase - - always_ff @(posedge clk) - if (transition) begin - // Si cache no quiere hacer una operación con memoria, se asignan - // las señales del core - mem_address <= cache_mem ? cache_mem_address : core_address_line; - mem_writedata <= cache_mem ? cache_mem_writedata : core_writedata_line; - mem_byteenable <= cache_mem ? 16'hffff : core_byteenable_line; - end - -endmodule diff --git a/rtl/cache/sram.sv b/rtl/cache/sram.sv deleted file mode 100644 index d63cdad..0000000 --- a/rtl/cache/sram.sv +++ /dev/null @@ -1,71 +0,0 @@ -`include "cache/defs.sv" - -module cache_sram -( - input logic clk, - rst_n, - - input addr_index index_rd, - index_wr, - input logic write_data, - write_state, - input addr_tag tag_wr, - input line data_wr, - input line_state state_wr, - - output addr_tag tag_rd, - output line data_rd, - output line_state state_rd -); - - // Existe un mito que habla de true dual-ports con byte-enables, - // probablemente no sea real: - // https://www.intel.com/content/www/us/en/docs/programmable/683082/21-3/ram-with-byte-enable-signals.html - - // Es una cache one way: cada índice mapea a cada línea de cache - // (directamente mapeada) - - // Define la cantidad de líneas de cache - // Cantidad de bits en addr_index = 12, entonces se le hace left shift 12 - // espacios a 1. Osea, 4096 líneas de cache. - // Tenemos 4kilo-líneas de caché. Cada línea es de 128bits, osea tenemos una - // caché de 64KBi. - localparam DEPTH = 1 << $bits(addr_index); - - // Estas tres secciones constituyen al caché. - // data_file: Donde se guarda la información cacheada. - // tag_file: Se guardan los tags de las líneas de caché. - // state_file: Se guarda el estado de cada línea de caché. (Acá están todos - // los estados de MESI) - line data_file[DEPTH] /*verilator public*/; - addr_tag tag_file[DEPTH] /*verilator public*/; - line_state state_file[DEPTH] /*verilator public*/; - - // 3 funciones principales: - // 1. Si se necesita escribir un dato: escribe en los tag y data files en - // la posición del index de escritura - // 2. Si se necesita escribir un estado: escribe en el state file en la - // posición del index de escritura - // 3. Cada ciclo retorna siempre lo que esté en todos los files en la - // posición de index de lectura - always_ff @(posedge clk) begin - if (write_data) begin - tag_file[index_wr] <= tag_wr; - data_file[index_wr] <= data_wr; - end - - if (write_state) - state_file[index_wr] <= state_wr; - - tag_rd <= tag_file[index_rd]; - data_rd <= data_file[index_rd]; - state_rd <= state_file[index_rd]; - end - - // Se inicializan todas las líneas del state file como INVALID - //FIXME: rst_n para state_file? - initial - for (int i = 0; i < DEPTH; ++i) - state_file[i] = INVALID; - -endmodule diff --git a/rtl/cache/token.sv b/rtl/cache/token.sv deleted file mode 100644 index cb3e59d..0000000 --- a/rtl/cache/token.sv +++ /dev/null @@ -1,57 +0,0 @@ -`include "cache/defs.sv" - -module cache_token -#(parameter TOKEN_AT_RESET=0) -( - input logic clk, - rst_n, - - input addr_tag core_tag, - input addr_index core_index, - - input ring_token in_token, // input del token - input logic in_token_valid, // se está recibiendo el token - - output ring_token out_token, // output del token - output logic out_token_valid, // se está enviando el token - - input logic send, - lock_line, - unlock_line, - output logic locked, - may_send -); - - logic may_send_if_token_held; - - // Solo se puede iniciar un request si se tiene el token y el token es - // válido - assign may_send = may_send_if_token_held && in_token_valid; - assign may_send_if_token_held - = (!in_token.e2.valid || in_token.e2.index != core_index || in_token.e2.tag != core_tag) - && (!in_token.e1.valid || in_token.e1.index != core_index || in_token.e1.tag != core_tag) - && (!in_token.e0.valid || in_token.e0.index != core_index || in_token.e0.tag != core_tag); - - always_ff @(posedge clk or negedge rst_n) - if (!rst_n) begin - out_token <= {($bits(out_token)){1'b0}}; - out_token_valid <= TOKEN_AT_RESET; - - locked <= 0; - end else begin - out_token.e0.tag <= core_tag; - out_token.e0.index <= core_index; - out_token.e0.valid <= may_send_if_token_held && (send || locked) && !unlock_line; - - out_token.e2 <= in_token.e1; - out_token.e1 <= in_token.e0; - out_token_valid <= in_token_valid; - - if (lock_line) - locked <= 1; - - if (unlock_line) - locked <= 0; - end - -endmodule diff --git a/rtl/core/alu/add.sv b/rtl/core/alu/add.sv deleted file mode 100644 index a15a6b6..0000000 --- a/rtl/core/alu/add.sv +++ /dev/null @@ -1,45 +0,0 @@ -module core_alu_add -# -( - parameter W=16, - parameter SUB=0 -) -( - input logic[W - 1:0] a, - b, - input logic c_in, - - output logic[W - 1:0] q, - output logic c, - v -); - - logic sgn_a, sgn_b, sgn_q, maybe_v; - logic[W:0] out; - - /* Quartus infiere dos sumadores si se zero-extendea el cin - * para complacer a Verilator, lo cual es malo para Fmax. - */ -`ifdef VERILATOR - logic[W:0] ext_carry; - assign ext_carry = {{W{1'b0}}, c_in}; -`else - logic ext_carry; - assign ext_carry = c_in; -`endif - - assign v = maybe_v & (sgn_a ^ sgn_q); - assign {c, q} = out; - assign {sgn_a, sgn_b, sgn_q} = {a[W - 1], b[W - 1], q[W - 1]}; - - generate - if(SUB) begin - assign out = {1'b1, a} - {1'b0, b} - ext_carry; - assign maybe_v = sgn_a ^ sgn_b; - end else begin - assign out = {1'b0, a} + {1'b0, b} + ext_carry; - assign maybe_v = sgn_a ~^ sgn_b; - end - endgenerate - -endmodule diff --git a/rtl/core/alu/alu.sv b/rtl/core/alu/alu.sv deleted file mode 100644 index c0ccd32..0000000 --- a/rtl/core/alu/alu.sv +++ /dev/null @@ -1,139 +0,0 @@ -`include "core/uarch.sv" -`include "core/decode/isa.sv" - -module core_alu -#(parameter W=16) -( - input alu_op op, - input logic[W - 1:0] a, - b, - input logic c_in, - c_logic, - - output logic[W - 1:0] q, - output psr_flags nzcv, - output logic v_valid -); - - logic c, v, c_add, c_sub, c_rsb, v_add, v_sub, v_rsb; - logic[W - 1:0] not_b, q_add, q_sub, q_rsb, q_and, q_bic, q_orr, q_xor; - - assign not_b = ~b; - - core_alu_add #(.W(W), .SUB(0)) op_add - ( - .q(q_add), - .c(c_add), - .v(v_add), - .c_in(c_in && !op `FIELD_ALUOP_ADD_CMN && op `FIELD_ALUOP_ADD_NOTCMN_ADC), - .* - ); - - core_alu_add #(.W(W), .SUB(1)) op_sub - ( - .q(q_sub), - .c(c_sub), - .v(v_sub), - .c_in(!c_in && op `FIELD_ALUOP_SUB_SBC), - .* - ); - - core_alu_add #(.W(W), .SUB(1)) op_rsb - ( - .a(b), - .b(a), - .q(q_rsb), - .c(c_rsb), - .v(v_rsb), - .c_in(!c_in && op `FIELD_ALUOP_RSB_RSC), - .* - ); - - core_alu_and #(.W(W)) op_and - ( - .q(q_and), - .* - ); - - core_alu_and #(.W(W)) op_bic - ( - .b(not_b), - .q(q_bic), - .* - ); - - core_alu_orr #(.W(W)) op_orr - ( - .q(q_orr), - .* - ); - - core_alu_xor #(.W(W)) op_xor - ( - .q(q_xor), - .* - ); - - always_comb begin - unique case(op) - `ALU_ADD, `ALU_ADC, `ALU_CMN: - q = q_add; - - `ALU_SUB, `ALU_SBC, `ALU_CMP: - q = q_sub; - - `ALU_RSB, `ALU_RSC: - q = q_rsb; - - `ALU_AND, `ALU_TST: - q = q_and; - - `ALU_BIC: - q = q_bic; - - `ALU_EOR, `ALU_TEQ: - q = q_xor; - - `ALU_ORR: - q = q_orr; - - `ALU_MOV: - q = b; - - `ALU_MVN: - q = not_b; - endcase - - v = 1'bx; - unique case(op) - `ALU_AND, `ALU_EOR, `ALU_TST, `ALU_TEQ, `ALU_ORR, `ALU_MOV, `ALU_BIC, `ALU_MVN: - c = c_logic; - - `ALU_ADD, `ALU_ADC, `ALU_CMN: begin - c = c_add; - v = v_add; - end - - `ALU_SUB, `ALU_SBC, `ALU_CMP: begin - c = c_sub; - v = v_sub; - end - - `ALU_RSB, `ALU_RSC: begin - c = c_rsb; - v = v_rsb; - end - endcase - - unique case(op) - `ALU_AND, `ALU_EOR, `ALU_TST, `ALU_TEQ, `ALU_ORR, `ALU_MOV, `ALU_BIC, `ALU_MVN: - v_valid = 0; - - `ALU_SUB, `ALU_RSB, `ALU_ADD, `ALU_ADC, `ALU_SBC, `ALU_RSC, `ALU_CMP, `ALU_CMN: - v_valid = 1; - endcase - end - - assign nzcv = {q[W - 1], q == 0, c, v}; - -endmodule diff --git a/rtl/core/alu/and.sv b/rtl/core/alu/and.sv deleted file mode 100644 index d119f24..0000000 --- a/rtl/core/alu/and.sv +++ /dev/null @@ -1,12 +0,0 @@ -module core_alu_and -#(parameter W=16) -( - input logic[W - 1:0] a, - b, - - output logic[W - 1:0] q -); - - assign q = a & b; - -endmodule diff --git a/rtl/core/alu/orr.sv b/rtl/core/alu/orr.sv deleted file mode 100644 index 1ee87c2..0000000 --- a/rtl/core/alu/orr.sv +++ /dev/null @@ -1,12 +0,0 @@ -module core_alu_orr -#(parameter W=16) -( - input logic[W - 1:0] a, - b, - - output logic[W - 1:0] q -); - - assign q = a | b; - -endmodule diff --git a/rtl/core/alu/xor.sv b/rtl/core/alu/xor.sv deleted file mode 100644 index f55dfc2..0000000 --- a/rtl/core/alu/xor.sv +++ /dev/null @@ -1,12 +0,0 @@ -module core_alu_xor -#(parameter W=16) -( - input logic[W - 1:0] a, - b, - - output logic[W - 1:0] q -); - - assign q = a ^ b; - -endmodule diff --git a/rtl/core/arm810.sv b/rtl/core/arm810.sv index cfe202a..66493e2 100644 --- a/rtl/core/arm810.sv +++ b/rtl/core/arm810.sv @@ -1,4 +1,4 @@ -`include "core/mmu/format.sv" +`include "core/mmu_format.sv" `include "core/uarch.sv" module arm810 diff --git a/rtl/core/control/branch.sv b/rtl/core/control/branch.sv deleted file mode 100644 index 0298b95..0000000 --- a/rtl/core/control/branch.sv +++ /dev/null @@ -1,30 +0,0 @@ -`include "core/uarch.sv" - -module core_control_branch -( - input logic clk, - rst_n, - - input insn_decode dec, - - input ctrl_cycle next_cycle, - input logic issue, - input ptr next_pc_visible, - - output logic branch, - output ptr branch_target -); - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - branch <= 1; - branch_target <= {$bits(branch_target){1'b0}}; - end else begin - branch <= 0; - if(next_cycle.issue && issue) begin - branch <= dec.ctrl.branch; - branch_target <= next_pc_visible + dec.branch.offset; - end - end - -endmodule diff --git a/rtl/core/control/control.sv b/rtl/core/control/control.sv deleted file mode 100644 index 27be940..0000000 --- a/rtl/core/control/control.sv +++ /dev/null @@ -1,183 +0,0 @@ -`include "core/uarch.sv" - -module core_control -( - input logic clk, - rst_n, - - input logic irq, - halt, - step, - - input insn_decode dec, - input ptr insn_pc, - input logic issue_abort, - input psr_mode mode, - input psr_intmask intmask, - input psr_flags flags, - alu_flags, - input word cpsr_rd, - spsr_rd, - rd_value_a, - rd_value_b, - q_alu, - q_shifter, - input logic c_shifter, - mem_ready, - mem_fault, - mem_ex_fail, - input word mem_data_rd, - input logic mul_ready, - input word mul_q_hi, - mul_q_lo, - coproc_read, - input logic high_vectors, - -`ifdef VERILATOR - input word insn, -`endif - - output logic halted, - stall, - branch, - writeback, - breakpoint, - update_flags, - c_logic, - output reg_num rd, - ra, - rb, - output ptr branch_target, - pc_visible, - output psr_mode rd_mode, - wr_mode, - output alu_op alu, - output word alu_a, - alu_b, - wr_value, - output shifter_control shifter, - output word shifter_base, - output logic[7:0] shifter_shift, - output ptr mem_addr, - output word mem_data_wr, - output logic[3:0] mem_data_be, - output logic mem_start, - mem_write, - mem_ex_lock, - mem_user, - output word mul_a, - mul_b, - mul_c_hi, - mul_c_lo, - output logic mul_add, - mul_long, - mul_start, - mul_signed, - coproc, - escalating, - psr_saved, - psr_write, - psr_wr_flags, - psr_wr_control, - output word psr_wr, - output coproc_decode coproc_ctrl -); - - ctrl_cycle cycle, next_cycle; - - core_control_cycles ctrl_cycles - ( - .* - ); - - logic bubble, next_bubble; - - core_control_stall ctrl_stall - ( - .* - ); - - ptr pc /*verilator public*/, next_pc_visible; - logic issue, undefined, prefetch_abort; - - core_control_issue ctrl_issue - ( - .* - ); - - logic rd_user; - - core_control_select ctrl_select - ( - .* - ); - - word mem_offset, ldst_read, strex_ok; - logic ldst, ldst_next, ldst_reject, ldst_writeback, pop_valid; - reg_num popped; - logic[1:0] ldst_shift; - - core_control_ldst ctrl_ldst - ( - .* - ); - - core_control_branch ctrl_branch - ( - .* - ); - - word saved_base; - logic trivial_shift, data_snd_shift_by_reg; - - core_control_data ctrl_data - ( - .* - ); - - logic mul; - reg_num mul_r_add_hi, mul_r_add_lo; - - core_control_mul ctrl_mul - ( - .* - ); - - word psr_wb; - logic psr, final_psr_write, final_restore_spsr; - - core_control_psr ctrl_psr - ( - .* - ); - - logic final_writeback, final_update_flags; - reg_num final_rd; - - core_control_writeback ctrl_wb - ( - .* - ); - - word exception_vector; - logic exception, exception_offset_pc; - psr_mode exception_mode; - - core_control_exception ctrl_exc - ( - .* - ); - - word coproc_wb; - - core_control_coproc ctrl_cp - ( - .* - ); - - core_control_debug ctrl_dbg - ( - .* - ); - -endmodule diff --git a/rtl/core/control/coproc.sv b/rtl/core/control/coproc.sv deleted file mode 100644 index 05ac655..0000000 --- a/rtl/core/control/coproc.sv +++ /dev/null @@ -1,32 +0,0 @@ -`include "core/uarch.sv" - -module core_control_coproc -( - input logic clk, - rst_n, - - input insn_decode dec, - input word coproc_read, - - input ctrl_cycle next_cycle, - input logic issue, - - output logic coproc, - output word coproc_wb, - output coproc_decode coproc_ctrl -); - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - coproc <= 0; - coproc_wb <= 0; - coproc_ctrl <= {$bits(coproc_ctrl){1'b0}}; - end else if(next_cycle.issue && issue) begin - coproc <= dec.ctrl.coproc; - coproc_ctrl <= dec.coproc; - end else if(next_cycle.coproc) begin - coproc <= 0; - coproc_wb <= coproc_read; - end - -endmodule diff --git a/rtl/core/control/cycles.sv b/rtl/core/control/cycles.sv deleted file mode 100644 index 772697d..0000000 --- a/rtl/core/control/cycles.sv +++ /dev/null @@ -1,148 +0,0 @@ -`include "core/uarch.sv" - -module core_control_cycles -( - input logic clk, - rst_n, - halt, - mul, - psr, - ldst, - bubble, - coproc, - exception, - mem_ready, - mem_fault, - mul_add, - mul_long, - mul_ready, - pop_valid, - trivial_shift, - ldst_reject, - ldst_writeback, - data_snd_shift_by_reg, - - output ctrl_cycle cycle, - next_cycle -); - - /* qts-qii51007-recommended-hdl.pdf, p. 66 - * In Quartus II integrated synthesis, the enumerated type that defines the states for the - * state machine must be of an unsigned integer type as in Example 13–52. If you do not - * specify the enumerated type as int unsigned, a signed int type is used by default. In - * this case, the Quartus II integrated synthesis synthesizes the design, but does not infer - * or optimize the logic as a state machine. - */ - enum int unsigned - { - ISSUE, - RD_INDIRECT_SHIFT, - WITH_SHIFT, - TRANSFER, - BASE_WRITEBACK, - ESCALATE, - EXCEPTION, - MUL, - MUL_ACC_LD, - MUL_HI_WB, - PSR, - COPROC - } state, next_state; - - // TODO: debe estar escrito de tal forma que Quartus infiera una FSM - - assign cycle.issue = state == ISSUE; - assign cycle.rd_indirect_shift = state == RD_INDIRECT_SHIFT; - assign cycle.with_shift = state == WITH_SHIFT; - assign cycle.transfer = state == TRANSFER; - assign cycle.base_writeback = state == BASE_WRITEBACK; - assign cycle.escalate = state == ESCALATE; - assign cycle.exception = state == EXCEPTION; - assign cycle.mul = state == MUL; - assign cycle.mul_acc_ld = state == MUL_ACC_LD; - assign cycle.mul_hi_wb = state == MUL_HI_WB; - assign cycle.psr = state == PSR; - assign cycle.coproc = state == COPROC; - - assign next_cycle.issue = next_state == ISSUE; - assign next_cycle.rd_indirect_shift = next_state == RD_INDIRECT_SHIFT; - assign next_cycle.with_shift = next_state == WITH_SHIFT; - assign next_cycle.transfer = next_state == TRANSFER; - assign next_cycle.base_writeback = next_state == BASE_WRITEBACK; - assign next_cycle.escalate = next_state == ESCALATE; - assign next_cycle.exception = next_state == EXCEPTION; - assign next_cycle.mul = next_state == MUL; - assign next_cycle.mul_acc_ld = next_state == MUL_ACC_LD; - assign next_cycle.mul_hi_wb = next_state == MUL_HI_WB; - assign next_cycle.psr = next_state == PSR; - assign next_cycle.coproc = next_state == COPROC; - - always_comb begin - next_state = ISSUE; - - unique case(state) - ISSUE: - if(exception) - next_state = ESCALATE; - else if(halt) - next_state = ISSUE; - else if(mul) - next_state = mul_add ? MUL_ACC_LD : MUL; - else if(data_snd_shift_by_reg) - next_state = RD_INDIRECT_SHIFT; - else if(!trivial_shift) - next_state = WITH_SHIFT; - else if(coproc) - next_state = COPROC; - - RD_INDIRECT_SHIFT: - if(!trivial_shift) - next_state = WITH_SHIFT; - - ESCALATE: - next_state = EXCEPTION; - - TRANSFER: begin - if(!mem_ready || pop_valid) - next_state = TRANSFER; - else if(ldst_writeback) - next_state = BASE_WRITEBACK; - - if(mem_ready && mem_fault) - next_state = ESCALATE; - - if(ldst_reject) - next_state = ISSUE; - end - - MUL: - if(!mul_ready) - next_state = MUL; - else if(mul_long) - next_state = MUL_HI_WB; - - MUL_ACC_LD: - next_state = MUL; - - /* Este default evita problemas de sintetizado, ya que Quartus - * asume que los casos mencionados son exhaustivos, provocando - * bugs muy difíciles de depurar. No es lo mismo que si se quita - * default. - */ - default: ; - endcase - - if(bubble) - next_state = ISSUE; - else if(next_state == ISSUE) begin - if(ldst) - next_state = TRANSFER; - else if(psr) - next_state = PSR; - end - end - - always_ff @(posedge clk or negedge rst_n) - state <= !rst_n ? ISSUE : next_state; - -endmodule diff --git a/rtl/core/control/data.sv b/rtl/core/control/data.sv deleted file mode 100644 index 3174ee1..0000000 --- a/rtl/core/control/data.sv +++ /dev/null @@ -1,117 +0,0 @@ -`include "core/uarch.sv" - -module core_control_data -( - input logic clk, - rst_n, - - input insn_decode dec, - input word rd_value_a, - rd_value_b, - input logic mem_ready, - mem_write, - input word mem_data_rd, - q_alu, - q_shifter, - input logic c_shifter, - - input ctrl_cycle cycle, - next_cycle, - input ptr pc_visible, - input logic ldst_next, - input logic[1:0] ldst_shift, - input word mem_offset, - input psr_flags flags, - input logic exception_offset_pc, - - output alu_op alu, - output word alu_a, - alu_b, - saved_base, - output shifter_control shifter, - output word shifter_base, - output logic[7:0] shifter_shift, - output logic c_logic, - trivial_shift, - data_snd_shift_by_reg -); - - logic data_snd_is_imm; - logic[5:0] data_shift_imm; - logic[11:0] data_imm; - - assign trivial_shift = shifter_shift == 0; - - always_comb begin - if(cycle.rd_indirect_shift) - shifter_shift = rd_value_b[7:0]; - else if(cycle.transfer) - shifter_shift = {3'b000, ldst_shift, 3'b000}; - else - shifter_shift = {2'b00, data_shift_imm}; - - if(cycle.transfer) - alu_a = saved_base; - else if(cycle.exception) - alu_a = {pc_visible, 2'b00}; - else - alu_a = rd_value_a; - - if(cycle.rd_indirect_shift || cycle.with_shift) - alu_b = saved_base; - else if(cycle.transfer) - alu_b = mem_offset; - else if(data_snd_is_imm) - alu_b = {{20{1'b0}}, data_imm}; - else - alu_b = rd_value_b; - - if(cycle.transfer) - shifter_base = mem_write ? rd_value_b : mem_data_rd; - else - shifter_base = alu_b; - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - alu <= {$bits(alu){1'b0}}; - c_logic <= 0; - shifter <= {$bits(shifter){1'b0}}; - data_imm <= {$bits(data_imm){1'b0}}; - saved_base <= 0; - data_shift_imm <= {$bits(data_shift_imm){1'b0}}; - data_snd_is_imm <= 0; - data_snd_shift_by_reg <= 0; - end else if(next_cycle.issue) begin - alu <= dec.data.op; - c_logic <= 0; - - data_imm <= dec.snd.imm; - data_shift_imm <= dec.snd.shift_imm; - data_snd_is_imm <= dec.snd.is_imm; - data_snd_shift_by_reg <= dec.snd.shift_by_reg; - - shifter.shr <= dec.snd.shr; - shifter.ror <= dec.snd.ror; - shifter.put_carry <= dec.snd.put_carry; - shifter.sign_extend <= dec.snd.sign_extend; - end else if(next_cycle.rd_indirect_shift) begin - saved_base <= rd_value_b; - data_snd_shift_by_reg <= 0; - end else if(next_cycle.with_shift) begin - c_logic <= c_shifter; - saved_base <= q_shifter; - end else if(next_cycle.transfer) begin - if(ldst_next) - saved_base <= q_alu; - - shifter.ror <= 0; - shifter.shr <= !mem_write; - end else if(next_cycle.exception) begin - alu <= `ALU_SUB; - // Either pc_visible - 0 (pc + 8) or pc_visible - 4 (pc + 4) - data_imm <= {9'd0, exception_offset_pc, 2'b00}; - data_snd_is_imm <= 1; - end - -endmodule diff --git a/rtl/core/control/debug.sv b/rtl/core/control/debug.sv deleted file mode 100644 index 35b1334..0000000 --- a/rtl/core/control/debug.sv +++ /dev/null @@ -1,25 +0,0 @@ -`include "core/uarch.sv" - -module core_control_debug -( - input logic clk, - rst_n, - step, - - input ctrl_cycle next_cycle, - input logic issue, - next_bubble, - input insn_decode dec, - - output logic breakpoint -); - - logic stable, step_trigger; - - assign stable = next_cycle.issue && !dec.ctrl.nop && !next_bubble; - assign breakpoint = stable && (dec.ctrl.bkpt || step_trigger); - - always @(posedge clk or negedge rst_n) - step_trigger <= !rst_n ? 0 : step && (step_trigger || stable) && !breakpoint; - -endmodule diff --git a/rtl/core/control/exception.sv b/rtl/core/control/exception.sv deleted file mode 100644 index 387e9c1..0000000 --- a/rtl/core/control/exception.sv +++ /dev/null @@ -1,70 +0,0 @@ -`include "core/uarch.sv" - -module core_control_exception -( - input logic clk, - rst_n, - - input ctrl_cycle cycle, - next_cycle, - input insn_decode dec, - input psr_intmask intmask, - input logic issue, - irq, - high_vectors, - undefined, - prefetch_abort, - mem_fault, - - output logic escalating, - exception, - exception_offset_pc, - output psr_mode exception_mode, - output word exception_vector -); - - logic pending_irq, syscall; - logic[2:0] vector_offset; - - //TODO: fiq - - assign exception = undefined || syscall || prefetch_abort || mem_fault || pending_irq; - assign escalating = cycle.escalate; - assign exception_vector = {{16{high_vectors}}, 11'b0, vector_offset, 2'b00}; - - always @(posedge clk or negedge rst_n) - if(!rst_n) begin - syscall <= 0; - pending_irq <= 0; - vector_offset <= 0; - exception_mode <= 0; - exception_offset_pc <= 0; - end else begin - if(next_cycle.issue) begin - syscall <= issue && dec.ctrl.swi; - pending_irq <= issue && irq && !intmask.i; - end - - // A2.6.10 Exception priorities - if(mem_fault) begin - vector_offset <= 3'b100; - exception_mode <= `MODE_ABT; - end else if(pending_irq) begin - vector_offset <= 3'b110; - exception_mode <= `MODE_IRQ; - end else if(prefetch_abort) begin - vector_offset <= 3'b011; - exception_mode <= `MODE_ABT; - end else if(undefined) begin - vector_offset <= 3'b001; - exception_mode <= `MODE_UND; - end else if(syscall) begin - vector_offset <= 3'b010; - exception_mode <= `MODE_SVC; - end - - if(next_cycle.escalate) - exception_offset_pc <= !mem_fault; - end - -endmodule diff --git a/rtl/core/control/issue.sv b/rtl/core/control/issue.sv deleted file mode 100644 index 5bd03e1..0000000 --- a/rtl/core/control/issue.sv +++ /dev/null @@ -1,80 +0,0 @@ -`include "core/uarch.sv" - -module core_control_issue -( - input logic clk, - rst_n, - - input logic halt, - irq, - - input insn_decode dec, - input ptr insn_pc, - input logic issue_abort, - - input ctrl_cycle next_cycle, - input logic next_bubble, - -`ifdef VERILATOR - input word insn, -`endif - - output logic issue, - undefined, - prefetch_abort, - output ptr pc, - pc_visible, - next_pc_visible -); - - logic valid; - -`ifdef VERILATOR - word bh0 /*verilator public*/, - bh1 /*verilator public*/, - bh2 /*verilator public*/, - bh3 /*verilator public*/; -`endif - - assign valid = !next_bubble && !halt; - assign issue = next_cycle.issue && dec.ctrl.execute && valid; - assign next_pc_visible = insn_pc + 2; - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - pc <= 0; - undefined <= 0; - pc_visible <= 2; - prefetch_abort <= 0; - -`ifdef VERILATOR - bh0 <= 0; - bh1 <= 0; - bh2 <= 0; - bh3 <= 0; -`endif - end else if(next_cycle.issue) begin - if(valid) begin - undefined <= dec.ctrl.undefined; - prefetch_abort <= issue_abort; - -`ifdef VERILATOR - if(dec.ctrl.undefined && !issue_abort) - $display("[core] undefined insn: [0x%08x] %08x", insn_pc << 2, insn); -`endif - end - - pc <= insn_pc; - pc_visible <= next_pc_visible; - -`ifdef VERILATOR - if(insn_pc != pc && insn_pc != pc + 1) begin - bh0 <= {pc, 2'b00}; - bh1 <= bh0; - bh2 <= bh1; - bh3 <= bh2; - end -`endif - end - -endmodule diff --git a/rtl/core/control/ldst/ldst.sv b/rtl/core/control/ldst/ldst.sv deleted file mode 100644 index aa5c957..0000000 --- a/rtl/core/control/ldst/ldst.sv +++ /dev/null @@ -1,129 +0,0 @@ -`include "core/uarch.sv" - -module core_control_ldst -( - input logic clk, - rst_n, - - input insn_decode dec, - input logic issue, - mem_ready, - mem_ex_fail, - input word rd_value_b, - q_alu, - q_shifter, - - input ctrl_cycle cycle, - next_cycle, - input word alu_a, - alu_b, - - output ptr mem_addr, - output logic[3:0] mem_data_be, - output word mem_data_wr, - mem_offset, - output logic mem_start, - mem_write, - mem_ex_lock, - mem_user, - pop_valid, - ldst, - ldst_next, - ldst_reject, - ldst_writeback, - output logic[1:0] ldst_shift, - output word ldst_read, - strex_ok, - output reg_num popped -); - - word base; - logic block_strex, increment, pre, sign_extend; - reg_num popped_upper, popped_lower; - reg_list mem_regs, next_regs_upper, next_regs_lower; - ldst_size size; - - assign popped = increment ? popped_lower : popped_upper; - assign ldst_next = !cycle.transfer || mem_ready; - assign mem_data_wr = mem_ex_lock ? alu_b : q_shifter; - - assign strex_ok = {31'd0, mem_ex_fail || block_strex}; - assign ldst_reject = mem_ex_lock && mem_write && block_strex; - - core_control_ldst_pop pop - ( - .regs(mem_regs), - .valid(pop_valid), - .next_upper(next_regs_upper), - .next_lower(next_regs_lower), - .pop_upper(popped_upper), - .pop_lower(popped_lower) - ); - - core_control_ldst_sizes sizes - ( - .addr(mem_addr), - .read(ldst_read), - .shift(ldst_shift), - .fault(), //TODO: alignment check - .byteenable(mem_data_be), - .* - ); - - always_ff @(posedge clk or negedge rst_n) - if (!rst_n) begin - pre <= 0; - ldst <= 0; - size <= LDST_WORD; - increment <= 0; - block_strex <= 1; - sign_extend <= 0; - ldst_writeback <= 0; - - base <= {$bits(base){1'b0}}; - mem_regs <= {$bits(mem_regs){1'b0}}; - mem_user <= 0; - mem_write <= 0; - mem_start <= 0; - mem_offset <= 0; - mem_ex_lock <= 0; - end else begin - if (mem_start) - mem_start <= 0; - - if (next_cycle.issue) begin - if (issue) begin - ldst <= dec.ctrl.ldst; - mem_user <= dec.ldst.unprivileged; - end - - pre <= dec.ldst.pre_indexed; - size <= dec.ldst.size; - increment <= dec.ldst.increment; - sign_extend <= dec.ldst.sign_extend; - ldst_writeback <= dec.ldst.writeback; - - mem_regs <= dec.ldst.regs; - mem_write <= !dec.ldst.load; - mem_ex_lock <= dec.ldst.exclusive; - end else if (next_cycle.transfer) begin - if (!cycle.transfer) begin - ldst <= 0; - mem_offset <= alu_b; - end - - if (ldst_next) begin - base <= pre ? q_alu : alu_a; - mem_regs <= increment ? next_regs_lower : next_regs_upper; - end - - mem_start <= (!cycle.transfer || (mem_ready && pop_valid)) && !ldst_reject; - - if (block_strex) - block_strex <= !mem_ex_lock || mem_write; - end else if (cycle.escalate) begin - ldst <= 0; - block_strex <= 1; - end - end -endmodule diff --git a/rtl/core/control/ldst/pop.sv b/rtl/core/control/ldst/pop.sv deleted file mode 100644 index 64dc04d..0000000 --- a/rtl/core/control/ldst/pop.sv +++ /dev/null @@ -1,56 +0,0 @@ -`include "core/uarch.sv" - -module core_control_ldst_pop -( - input reg_list regs, - - output logic valid, - output reg_list next_upper, - next_lower, - output reg_num pop_upper, - pop_lower -); - - assign valid = regs != 16'b0; - - always_comb begin - unique casez(regs) - 16'b???????????????1: begin pop_lower = 4'h0; next_lower = {regs[15:1], 1'b0}; end - 16'b??????????????10: begin pop_lower = 4'h1; next_lower = {regs[15:2], 2'b0}; end - 16'b?????????????100: begin pop_lower = 4'h2; next_lower = {regs[15:3], 3'b0}; end - 16'b????????????1000: begin pop_lower = 4'h3; next_lower = {regs[15:4], 4'b0}; end - 16'b???????????10000: begin pop_lower = 4'h4; next_lower = {regs[15:5], 5'b0}; end - 16'b??????????100000: begin pop_lower = 4'h5; next_lower = {regs[15:6], 6'b0}; end - 16'b?????????1000000: begin pop_lower = 4'h6; next_lower = {regs[15:7], 7'b0}; end - 16'b????????10000000: begin pop_lower = 4'h7; next_lower = {regs[15:8], 8'b0}; end - 16'b???????100000000: begin pop_lower = 4'h8; next_lower = {regs[15:9], 9'b0}; end - 16'b??????1000000000: begin pop_lower = 4'h9; next_lower = {regs[15:10], 10'b0}; end - 16'b?????10000000000: begin pop_lower = 4'ha; next_lower = {regs[15:11], 11'b0}; end - 16'b????100000000000: begin pop_lower = 4'hb; next_lower = {regs[15:12], 12'b0}; end - 16'b???1000000000000: begin pop_lower = 4'hc; next_lower = {regs[15:13], 13'b0}; end - 16'b??10000000000000: begin pop_lower = 4'hd; next_lower = {regs[15:14], 14'b0}; end - 16'b?100000000000000: begin pop_lower = 4'he; next_lower = {regs[15], 15'b0}; end - default: begin pop_lower = 4'hf; next_lower = 16'b0; end - endcase - - unique casez(regs) - 16'b1???????????????: begin pop_upper = 4'hf; next_upper = { 1'b0, regs[14:0]}; end - 16'b01??????????????: begin pop_upper = 4'he; next_upper = { 2'b0, regs[13:0]}; end - 16'b001?????????????: begin pop_upper = 4'hd; next_upper = { 3'b0, regs[12:0]}; end - 16'b0001????????????: begin pop_upper = 4'hc; next_upper = { 4'b0, regs[11:0]}; end - 16'b00001???????????: begin pop_upper = 4'hb; next_upper = { 5'b0, regs[10:0]}; end - 16'b000001??????????: begin pop_upper = 4'ha; next_upper = { 6'b0, regs[9:0]}; end - 16'b0000001?????????: begin pop_upper = 4'h9; next_upper = { 7'b0, regs[8:0]}; end - 16'b00000001????????: begin pop_upper = 4'h8; next_upper = { 8'b0, regs[7:0]}; end - 16'b000000001???????: begin pop_upper = 4'h7; next_upper = { 9'b0, regs[6:0]}; end - 16'b0000000001??????: begin pop_upper = 4'h6; next_upper = {10'b0, regs[5:0]}; end - 16'b00000000001?????: begin pop_upper = 4'h5; next_upper = {11'b0, regs[4:0]}; end - 16'b000000000001????: begin pop_upper = 4'h4; next_upper = {12'b0, regs[3:0]}; end - 16'b0000000000001???: begin pop_upper = 4'h3; next_upper = {13'b0, regs[2:0]}; end - 16'b00000000000001??: begin pop_upper = 4'h2; next_upper = {14'b0, regs[1:0]}; end - 16'b000000000000001?: begin pop_upper = 4'h1; next_upper = {15'b0, regs[0]}; end - default: begin pop_upper = 4'h0; next_upper = 16'b0; end - endcase - end - -endmodule diff --git a/rtl/core/control/ldst/sizes.sv b/rtl/core/control/ldst/sizes.sv deleted file mode 100644 index dff4662..0000000 --- a/rtl/core/control/ldst/sizes.sv +++ /dev/null @@ -1,46 +0,0 @@ -`include "core/uarch.sv" - -module core_control_ldst_sizes -( - input word base, - q_shifter, - input ldst_size size, - input logic sign_extend, - - output ptr addr, - output word read, - output logic[1:0] shift, - output logic[3:0] byteenable, - output logic fault -); - - assign {addr, shift} = base; - - always_comb - unique case(size) - LDST_BYTE: begin - read = {{24{q_shifter[7] && sign_extend}}, q_shifter[7:0]}; - fault = 0; - - unique case(shift) - 2'b00: byteenable = 4'b0001; - 2'b01: byteenable = 4'b0010; - 2'b10: byteenable = 4'b0100; - 2'b11: byteenable = 4'b1000; - endcase - end - - LDST_HALF: begin - read = {{16{q_shifter[15] && sign_extend}}, q_shifter[15:0]}; - fault = shift[0]; - byteenable = shift[1] ? 4'b1100 : 4'b0011; - end - - LDST_WORD: begin - read = q_shifter; - fault = shift[1] || shift[0]; - byteenable = 4'b1111; - end - endcase - -endmodule diff --git a/rtl/core/control/mul_fu.sv b/rtl/core/control/mul_fu.sv deleted file mode 100644 index 8352435..0000000 --- a/rtl/core/control/mul_fu.sv +++ /dev/null @@ -1,67 +0,0 @@ -`include "core/uarch.sv" - -module core_control_mul -( - input logic clk, - rst_n, - - input insn_decode dec, - input logic mul_ready, - input word rd_value_a, - rd_value_b, - - input ctrl_cycle cycle, - next_cycle, - input logic issue, - - output word mul_a, - mul_b, - mul_c_hi, - mul_c_lo, - output reg_num mul_r_add_hi, - mul_r_add_lo, - output logic mul, - mul_add, - mul_long, - mul_start, - mul_signed -); - - word hold_a, hold_b; - - assign {mul_c_hi, mul_c_lo} = {rd_value_a, rd_value_b}; - assign {mul_a, mul_b} = mul_add ? {hold_a, hold_b} : {rd_value_a, rd_value_b}; - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - mul <= 0; - mul_add <= 0; - mul_long <= 0; - mul_start <= 0; - mul_signed <= 0; - mul_r_add_hi <= {$bits(mul_r_add_hi){1'b0}}; - mul_r_add_lo <= {$bits(mul_r_add_lo){1'b0}}; - - hold_a <= 0; - hold_b <= 0; - end else begin - mul_start <= 0; - - if(next_cycle.issue) begin - mul <= issue && dec.ctrl.mul; - mul_add <= dec.mul.add; - mul_long <= dec.mul.long_mul; - mul_signed <= dec.mul.signed_mul; - mul_r_add_hi <= dec.mul.r_add_hi; - mul_r_add_lo <= dec.mul.r_add_lo; - end else if(next_cycle.mul) - mul_start <= !cycle.mul; - else if(next_cycle.mul_acc_ld) begin - hold_a <= rd_value_a; - hold_b <= rd_value_b; - end - end - - //TODO: mul update_flags - -endmodule diff --git a/rtl/core/control/select.sv b/rtl/core/control/select.sv deleted file mode 100644 index dc04282..0000000 --- a/rtl/core/control/select.sv +++ /dev/null @@ -1,80 +0,0 @@ -`include "core/uarch.sv" - -module core_control_select -( - input logic clk, - rst_n, - - input insn_decode dec, - - input ctrl_cycle next_cycle, - input psr_mode mode, - input logic issue, - mem_ready, - pop_valid, - ldst_next, - input reg_num popped, - final_rd, - mul_r_add_lo, - mul_r_add_hi, - - output reg_num ra, - rb, - output psr_mode rd_mode, - wr_mode, - output logic rd_user -); - - logic wr_user; - reg_num r_shift, last_ra, last_rb; - - assign rd_mode = rd_user ? `MODE_USR : mode; - assign wr_mode = wr_user ? `MODE_USR : mode; - - always_comb begin - ra = last_ra; - rb = last_rb; - - if(next_cycle.issue) begin - ra = dec.data.rn; - rb = dec.snd.r; - end else if(next_cycle.rd_indirect_shift) - rb = r_shift; - else if(next_cycle.transfer) begin - if(ldst_next) - // final_rd viene de dec.ldst.rd - rb = pop_valid ? popped : final_rd; - end else if(next_cycle.mul_acc_ld) begin - ra = mul_r_add_hi; - rb = mul_r_add_lo; - end - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - last_ra <= {$bits(ra){1'b0}}; - last_rb <= {$bits(rb){1'b0}}; - r_shift <= {$bits(r_shift){1'b0}}; - - rd_user <= 0; - wr_user <= 0; - end else begin - last_ra <= ra; - last_rb <= rb; - - if(rd_user && next_cycle.transfer) - wr_user <= 1; - - if(rd_user && !next_cycle.transfer) - rd_user <= 0; - - if(wr_user && !next_cycle.transfer) - wr_user <= 0; - - if(next_cycle.issue) begin - r_shift <= dec.snd.r_shift; - rd_user <= issue && dec.ctrl.ldst && dec.ldst.user_regs; - end - end - -endmodule diff --git a/rtl/core/control/stall.sv b/rtl/core/control/stall.sv deleted file mode 100644 index 02a7552..0000000 --- a/rtl/core/control/stall.sv +++ /dev/null @@ -1,42 +0,0 @@ -`include "core/uarch.sv" - -module core_control_stall -( - input logic clk, - rst_n, - halt, - - input insn_decode dec, - - input ctrl_cycle next_cycle, - input logic rd_user, - final_update_flags, - final_restore_spsr, - final_psr_write, - final_writeback, - input reg_num final_rd, - - output logic halted, - stall, - bubble, - next_bubble -); - - logic pc_rd_hazard, pc_wr_hazard, rn_pc_hazard, snd_pc_hazard, psr_hazard, flags_hazard; - - assign stall = !next_cycle.issue || next_bubble || halt; - assign halted = halt && !next_bubble && next_cycle.issue; - assign next_bubble = pc_rd_hazard || pc_wr_hazard || flags_hazard || psr_hazard || rd_user; - - //FIXME: pc_rd_hazard no debería definirse sin final_writeback? - assign psr_hazard = final_psr_write || final_restore_spsr; - assign pc_rd_hazard = final_writeback && (rn_pc_hazard || snd_pc_hazard); - assign pc_wr_hazard = final_writeback && final_rd == `R15; - assign rn_pc_hazard = dec.data.uses_rn && dec.data.rn == `R15; - assign flags_hazard = dec.ctrl.conditional && final_update_flags; - assign snd_pc_hazard = !dec.snd.is_imm && dec.snd.r == `R15; - - always_ff @(posedge clk or negedge rst_n) - bubble <= !rst_n ? 0 : next_cycle.issue && next_bubble; - -endmodule diff --git a/rtl/core/control/status.sv b/rtl/core/control/status.sv deleted file mode 100644 index 6616bc9..0000000 --- a/rtl/core/control/status.sv +++ /dev/null @@ -1,81 +0,0 @@ -`include "core/uarch.sv" - -module core_control_psr -( - input logic clk, - rst_n, - - input insn_decode dec, - input word cpsr_rd, - spsr_rd, - alu_b, - input psr_mode exception_mode, - - input ctrl_cycle cycle, - next_cycle, - input logic issue, - - output logic psr, - psr_saved, - psr_write, - psr_wr_flags, - psr_wr_control, - final_psr_write, - final_restore_spsr, - output word psr_wb, - psr_wr -); - - word exception_spsr; - - assign psr_wb = psr_saved ? spsr_rd : cpsr_rd; - - always_comb begin - psr_write = 0; - - if(next_cycle.issue) - psr_write = final_psr_write || final_restore_spsr; - - if(cycle.escalate || cycle.exception) - psr_write = 1; - - if(cycle.escalate) - //TODO: F (FIQ) no cambia siempre - psr_wr = {24'b0, 3'b110, exception_mode}; - else if(cycle.exception) - psr_wr = exception_spsr; - else - psr_wr = final_restore_spsr ? spsr_rd : alu_b; - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - psr <= 0; - psr_saved <= 0; - psr_wr_flags <= 0; - psr_wr_control <= 0; - - exception_spsr <= 0; - final_psr_write <= 0; - final_restore_spsr <= 0; - end else if(next_cycle.issue) begin - psr <= issue && dec.ctrl.psr; - psr_saved <= dec.psr.saved; - psr_wr_flags <= dec.psr.wr_flags; - psr_wr_control <= dec.psr.wr_control; - - final_psr_write <= issue && dec.psr.write; - final_restore_spsr <= issue && dec.psr.restore_spsr; - end else if(next_cycle.escalate) begin - psr_saved <= 0; - psr_wr_flags <= 0; - psr_wr_control <= 1; - exception_spsr <= cpsr_rd; - end else if(next_cycle.exception) begin - psr <= 0; - psr_saved <= 1; - psr_wr_flags <= 1; - end else if(next_cycle.psr) - psr <= 0; - -endmodule diff --git a/rtl/core/control/writeback.sv b/rtl/core/control/writeback.sv deleted file mode 100644 index 027a7d7..0000000 --- a/rtl/core/control/writeback.sv +++ /dev/null @@ -1,128 +0,0 @@ -`include "core/uarch.sv" - -module core_control_writeback -( - input logic clk, - rst_n, - - input insn_decode dec, - input psr_flags alu_flags, - input word q_alu, - ldst_read, - input logic mem_ready, - mem_ex_lock, - mem_write, - input word mul_q_hi, - mul_q_lo, - strex_ok, - - input ctrl_cycle cycle, - next_cycle, - input word saved_base, - exception_vector, - psr_wb, - coproc_wb, - input reg_num ra, - popped, - mul_r_add_hi, - input logic issue, - pop_valid, - ldst_next, - ldst_reject, - - output reg_num rd, - final_rd, - output logic writeback, - final_writeback, - update_flags, - final_update_flags, - output word wr_value -); - - reg_num last_rd; - - always_comb begin - rd = last_rd; - if(next_cycle.transfer) begin - if(mem_ready) - rd = final_rd; - end else if(next_cycle.issue || next_cycle.base_writeback) - rd = final_rd; - else if(next_cycle.exception) - rd = `R15; - else if(next_cycle.mul_hi_wb) - rd = mul_r_add_hi; - - if(next_cycle.issue) - writeback = final_writeback; - else if(next_cycle.transfer) - writeback = mem_ready && !mem_write; - else if(next_cycle.base_writeback) - writeback = !mem_write; - else if(next_cycle.exception || next_cycle.mul_hi_wb) - writeback = 1; - else - writeback = 0; - - if(cycle.transfer) - wr_value = (mem_ex_lock && mem_write) ? strex_ok : ldst_read; - else if(cycle.base_writeback) - wr_value = saved_base; - else if(cycle.mul || cycle.mul_hi_wb) - wr_value = mul_q_lo; - else if(cycle.psr) - wr_value = psr_wb; - else if(cycle.coproc) - wr_value = coproc_wb; - else - // Ruta combinacional larga - wr_value = q_alu; - - if(next_cycle.transfer) begin - if(mem_ready) - wr_value = ldst_read; - end else if(next_cycle.base_writeback) - wr_value = ldst_read; - else if(next_cycle.exception) - wr_value = exception_vector; - else if(next_cycle.mul_hi_wb) - wr_value = mul_q_hi; - - update_flags = 0; - if(next_cycle.issue) - update_flags = final_update_flags; - else if(next_cycle.exception) - update_flags = 0; - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - last_rd <= 0; - final_rd <= 0; - final_writeback <= 0; - final_update_flags <= 0; - end else begin - last_rd <= rd; - - if(next_cycle.issue) - final_rd <= dec.data.rd; - else if(next_cycle.transfer) begin - if(ldst_next && pop_valid) - final_rd <= popped; - end else if(next_cycle.base_writeback) - final_rd <= ra; - else if(next_cycle.exception) - final_rd <= `R14; - - if(next_cycle.issue) - final_writeback <= issue && dec.ctrl.writeback; - else if(next_cycle.exception) - final_writeback <= 1; - - if(next_cycle.issue) - final_update_flags <= issue && dec.psr.update_flags; - else if(next_cycle.exception) - final_update_flags <= 0; - end - -endmodule diff --git a/rtl/core/core_alu.sv b/rtl/core/core_alu.sv new file mode 100644 index 0000000..6dafa65 --- /dev/null +++ b/rtl/core/core_alu.sv @@ -0,0 +1,139 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_alu +#(parameter W=16) +( + input alu_op op, + input logic[W - 1:0] a, + b, + input logic c_in, + c_logic, + + output logic[W - 1:0] q, + output psr_flags nzcv, + output logic v_valid +); + + logic c, v, c_add, c_sub, c_rsb, v_add, v_sub, v_rsb; + logic[W - 1:0] not_b, q_add, q_sub, q_rsb, q_and, q_bic, q_orr, q_xor; + + assign not_b = ~b; + + core_alu_add #(.W(W), .SUB(0)) op_add + ( + .q(q_add), + .c(c_add), + .v(v_add), + .c_in(c_in && !op `FIELD_ALUOP_ADD_CMN && op `FIELD_ALUOP_ADD_NOTCMN_ADC), + .* + ); + + core_alu_add #(.W(W), .SUB(1)) op_sub + ( + .q(q_sub), + .c(c_sub), + .v(v_sub), + .c_in(!c_in && op `FIELD_ALUOP_SUB_SBC), + .* + ); + + core_alu_add #(.W(W), .SUB(1)) op_rsb + ( + .a(b), + .b(a), + .q(q_rsb), + .c(c_rsb), + .v(v_rsb), + .c_in(!c_in && op `FIELD_ALUOP_RSB_RSC), + .* + ); + + core_alu_and #(.W(W)) op_and + ( + .q(q_and), + .* + ); + + core_alu_and #(.W(W)) op_bic + ( + .b(not_b), + .q(q_bic), + .* + ); + + core_alu_orr #(.W(W)) op_orr + ( + .q(q_orr), + .* + ); + + core_alu_xor #(.W(W)) op_xor + ( + .q(q_xor), + .* + ); + + always_comb begin + unique case(op) + `ALU_ADD, `ALU_ADC, `ALU_CMN: + q = q_add; + + `ALU_SUB, `ALU_SBC, `ALU_CMP: + q = q_sub; + + `ALU_RSB, `ALU_RSC: + q = q_rsb; + + `ALU_AND, `ALU_TST: + q = q_and; + + `ALU_BIC: + q = q_bic; + + `ALU_EOR, `ALU_TEQ: + q = q_xor; + + `ALU_ORR: + q = q_orr; + + `ALU_MOV: + q = b; + + `ALU_MVN: + q = not_b; + endcase + + v = 1'bx; + unique case(op) + `ALU_AND, `ALU_EOR, `ALU_TST, `ALU_TEQ, `ALU_ORR, `ALU_MOV, `ALU_BIC, `ALU_MVN: + c = c_logic; + + `ALU_ADD, `ALU_ADC, `ALU_CMN: begin + c = c_add; + v = v_add; + end + + `ALU_SUB, `ALU_SBC, `ALU_CMP: begin + c = c_sub; + v = v_sub; + end + + `ALU_RSB, `ALU_RSC: begin + c = c_rsb; + v = v_rsb; + end + endcase + + unique case(op) + `ALU_AND, `ALU_EOR, `ALU_TST, `ALU_TEQ, `ALU_ORR, `ALU_MOV, `ALU_BIC, `ALU_MVN: + v_valid = 0; + + `ALU_SUB, `ALU_RSB, `ALU_ADD, `ALU_ADC, `ALU_SBC, `ALU_RSC, `ALU_CMP, `ALU_CMN: + v_valid = 1; + endcase + end + + assign nzcv = {q[W - 1], q == 0, c, v}; + +endmodule diff --git a/rtl/core/core_alu_add.sv b/rtl/core/core_alu_add.sv new file mode 100644 index 0000000..a15a6b6 --- /dev/null +++ b/rtl/core/core_alu_add.sv @@ -0,0 +1,45 @@ +module core_alu_add +# +( + parameter W=16, + parameter SUB=0 +) +( + input logic[W - 1:0] a, + b, + input logic c_in, + + output logic[W - 1:0] q, + output logic c, + v +); + + logic sgn_a, sgn_b, sgn_q, maybe_v; + logic[W:0] out; + + /* Quartus infiere dos sumadores si se zero-extendea el cin + * para complacer a Verilator, lo cual es malo para Fmax. + */ +`ifdef VERILATOR + logic[W:0] ext_carry; + assign ext_carry = {{W{1'b0}}, c_in}; +`else + logic ext_carry; + assign ext_carry = c_in; +`endif + + assign v = maybe_v & (sgn_a ^ sgn_q); + assign {c, q} = out; + assign {sgn_a, sgn_b, sgn_q} = {a[W - 1], b[W - 1], q[W - 1]}; + + generate + if(SUB) begin + assign out = {1'b1, a} - {1'b0, b} - ext_carry; + assign maybe_v = sgn_a ^ sgn_b; + end else begin + assign out = {1'b0, a} + {1'b0, b} + ext_carry; + assign maybe_v = sgn_a ~^ sgn_b; + end + endgenerate + +endmodule diff --git a/rtl/core/core_alu_and.sv b/rtl/core/core_alu_and.sv new file mode 100644 index 0000000..d119f24 --- /dev/null +++ b/rtl/core/core_alu_and.sv @@ -0,0 +1,12 @@ +module core_alu_and +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a & b; + +endmodule diff --git a/rtl/core/core_alu_orr.sv b/rtl/core/core_alu_orr.sv new file mode 100644 index 0000000..1ee87c2 --- /dev/null +++ b/rtl/core/core_alu_orr.sv @@ -0,0 +1,12 @@ +module core_alu_orr +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a | b; + +endmodule diff --git a/rtl/core/core_alu_xor.sv b/rtl/core/core_alu_xor.sv new file mode 100644 index 0000000..f55dfc2 --- /dev/null +++ b/rtl/core/core_alu_xor.sv @@ -0,0 +1,12 @@ +module core_alu_xor +#(parameter W=16) +( + input logic[W - 1:0] a, + b, + + output logic[W - 1:0] q +); + + assign q = a ^ b; + +endmodule diff --git a/rtl/core/core_control.sv b/rtl/core/core_control.sv new file mode 100644 index 0000000..27be940 --- /dev/null +++ b/rtl/core/core_control.sv @@ -0,0 +1,183 @@ +`include "core/uarch.sv" + +module core_control +( + input logic clk, + rst_n, + + input logic irq, + halt, + step, + + input insn_decode dec, + input ptr insn_pc, + input logic issue_abort, + input psr_mode mode, + input psr_intmask intmask, + input psr_flags flags, + alu_flags, + input word cpsr_rd, + spsr_rd, + rd_value_a, + rd_value_b, + q_alu, + q_shifter, + input logic c_shifter, + mem_ready, + mem_fault, + mem_ex_fail, + input word mem_data_rd, + input logic mul_ready, + input word mul_q_hi, + mul_q_lo, + coproc_read, + input logic high_vectors, + +`ifdef VERILATOR + input word insn, +`endif + + output logic halted, + stall, + branch, + writeback, + breakpoint, + update_flags, + c_logic, + output reg_num rd, + ra, + rb, + output ptr branch_target, + pc_visible, + output psr_mode rd_mode, + wr_mode, + output alu_op alu, + output word alu_a, + alu_b, + wr_value, + output shifter_control shifter, + output word shifter_base, + output logic[7:0] shifter_shift, + output ptr mem_addr, + output word mem_data_wr, + output logic[3:0] mem_data_be, + output logic mem_start, + mem_write, + mem_ex_lock, + mem_user, + output word mul_a, + mul_b, + mul_c_hi, + mul_c_lo, + output logic mul_add, + mul_long, + mul_start, + mul_signed, + coproc, + escalating, + psr_saved, + psr_write, + psr_wr_flags, + psr_wr_control, + output word psr_wr, + output coproc_decode coproc_ctrl +); + + ctrl_cycle cycle, next_cycle; + + core_control_cycles ctrl_cycles + ( + .* + ); + + logic bubble, next_bubble; + + core_control_stall ctrl_stall + ( + .* + ); + + ptr pc /*verilator public*/, next_pc_visible; + logic issue, undefined, prefetch_abort; + + core_control_issue ctrl_issue + ( + .* + ); + + logic rd_user; + + core_control_select ctrl_select + ( + .* + ); + + word mem_offset, ldst_read, strex_ok; + logic ldst, ldst_next, ldst_reject, ldst_writeback, pop_valid; + reg_num popped; + logic[1:0] ldst_shift; + + core_control_ldst ctrl_ldst + ( + .* + ); + + core_control_branch ctrl_branch + ( + .* + ); + + word saved_base; + logic trivial_shift, data_snd_shift_by_reg; + + core_control_data ctrl_data + ( + .* + ); + + logic mul; + reg_num mul_r_add_hi, mul_r_add_lo; + + core_control_mul ctrl_mul + ( + .* + ); + + word psr_wb; + logic psr, final_psr_write, final_restore_spsr; + + core_control_psr ctrl_psr + ( + .* + ); + + logic final_writeback, final_update_flags; + reg_num final_rd; + + core_control_writeback ctrl_wb + ( + .* + ); + + word exception_vector; + logic exception, exception_offset_pc; + psr_mode exception_mode; + + core_control_exception ctrl_exc + ( + .* + ); + + word coproc_wb; + + core_control_coproc ctrl_cp + ( + .* + ); + + core_control_debug ctrl_dbg + ( + .* + ); + +endmodule diff --git a/rtl/core/core_control_branch.sv b/rtl/core/core_control_branch.sv new file mode 100644 index 0000000..0298b95 --- /dev/null +++ b/rtl/core/core_control_branch.sv @@ -0,0 +1,30 @@ +`include "core/uarch.sv" + +module core_control_branch +( + input logic clk, + rst_n, + + input insn_decode dec, + + input ctrl_cycle next_cycle, + input logic issue, + input ptr next_pc_visible, + + output logic branch, + output ptr branch_target +); + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + branch <= 1; + branch_target <= {$bits(branch_target){1'b0}}; + end else begin + branch <= 0; + if(next_cycle.issue && issue) begin + branch <= dec.ctrl.branch; + branch_target <= next_pc_visible + dec.branch.offset; + end + end + +endmodule diff --git a/rtl/core/core_control_coproc.sv b/rtl/core/core_control_coproc.sv new file mode 100644 index 0000000..05ac655 --- /dev/null +++ b/rtl/core/core_control_coproc.sv @@ -0,0 +1,32 @@ +`include "core/uarch.sv" + +module core_control_coproc +( + input logic clk, + rst_n, + + input insn_decode dec, + input word coproc_read, + + input ctrl_cycle next_cycle, + input logic issue, + + output logic coproc, + output word coproc_wb, + output coproc_decode coproc_ctrl +); + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + coproc <= 0; + coproc_wb <= 0; + coproc_ctrl <= {$bits(coproc_ctrl){1'b0}}; + end else if(next_cycle.issue && issue) begin + coproc <= dec.ctrl.coproc; + coproc_ctrl <= dec.coproc; + end else if(next_cycle.coproc) begin + coproc <= 0; + coproc_wb <= coproc_read; + end + +endmodule diff --git a/rtl/core/core_control_cycles.sv b/rtl/core/core_control_cycles.sv new file mode 100644 index 0000000..772697d --- /dev/null +++ b/rtl/core/core_control_cycles.sv @@ -0,0 +1,148 @@ +`include "core/uarch.sv" + +module core_control_cycles +( + input logic clk, + rst_n, + halt, + mul, + psr, + ldst, + bubble, + coproc, + exception, + mem_ready, + mem_fault, + mul_add, + mul_long, + mul_ready, + pop_valid, + trivial_shift, + ldst_reject, + ldst_writeback, + data_snd_shift_by_reg, + + output ctrl_cycle cycle, + next_cycle +); + + /* qts-qii51007-recommended-hdl.pdf, p. 66 + * In Quartus II integrated synthesis, the enumerated type that defines the states for the + * state machine must be of an unsigned integer type as in Example 13–52. If you do not + * specify the enumerated type as int unsigned, a signed int type is used by default. In + * this case, the Quartus II integrated synthesis synthesizes the design, but does not infer + * or optimize the logic as a state machine. + */ + enum int unsigned + { + ISSUE, + RD_INDIRECT_SHIFT, + WITH_SHIFT, + TRANSFER, + BASE_WRITEBACK, + ESCALATE, + EXCEPTION, + MUL, + MUL_ACC_LD, + MUL_HI_WB, + PSR, + COPROC + } state, next_state; + + // TODO: debe estar escrito de tal forma que Quartus infiera una FSM + + assign cycle.issue = state == ISSUE; + assign cycle.rd_indirect_shift = state == RD_INDIRECT_SHIFT; + assign cycle.with_shift = state == WITH_SHIFT; + assign cycle.transfer = state == TRANSFER; + assign cycle.base_writeback = state == BASE_WRITEBACK; + assign cycle.escalate = state == ESCALATE; + assign cycle.exception = state == EXCEPTION; + assign cycle.mul = state == MUL; + assign cycle.mul_acc_ld = state == MUL_ACC_LD; + assign cycle.mul_hi_wb = state == MUL_HI_WB; + assign cycle.psr = state == PSR; + assign cycle.coproc = state == COPROC; + + assign next_cycle.issue = next_state == ISSUE; + assign next_cycle.rd_indirect_shift = next_state == RD_INDIRECT_SHIFT; + assign next_cycle.with_shift = next_state == WITH_SHIFT; + assign next_cycle.transfer = next_state == TRANSFER; + assign next_cycle.base_writeback = next_state == BASE_WRITEBACK; + assign next_cycle.escalate = next_state == ESCALATE; + assign next_cycle.exception = next_state == EXCEPTION; + assign next_cycle.mul = next_state == MUL; + assign next_cycle.mul_acc_ld = next_state == MUL_ACC_LD; + assign next_cycle.mul_hi_wb = next_state == MUL_HI_WB; + assign next_cycle.psr = next_state == PSR; + assign next_cycle.coproc = next_state == COPROC; + + always_comb begin + next_state = ISSUE; + + unique case(state) + ISSUE: + if(exception) + next_state = ESCALATE; + else if(halt) + next_state = ISSUE; + else if(mul) + next_state = mul_add ? MUL_ACC_LD : MUL; + else if(data_snd_shift_by_reg) + next_state = RD_INDIRECT_SHIFT; + else if(!trivial_shift) + next_state = WITH_SHIFT; + else if(coproc) + next_state = COPROC; + + RD_INDIRECT_SHIFT: + if(!trivial_shift) + next_state = WITH_SHIFT; + + ESCALATE: + next_state = EXCEPTION; + + TRANSFER: begin + if(!mem_ready || pop_valid) + next_state = TRANSFER; + else if(ldst_writeback) + next_state = BASE_WRITEBACK; + + if(mem_ready && mem_fault) + next_state = ESCALATE; + + if(ldst_reject) + next_state = ISSUE; + end + + MUL: + if(!mul_ready) + next_state = MUL; + else if(mul_long) + next_state = MUL_HI_WB; + + MUL_ACC_LD: + next_state = MUL; + + /* Este default evita problemas de sintetizado, ya que Quartus + * asume que los casos mencionados son exhaustivos, provocando + * bugs muy difíciles de depurar. No es lo mismo que si se quita + * default. + */ + default: ; + endcase + + if(bubble) + next_state = ISSUE; + else if(next_state == ISSUE) begin + if(ldst) + next_state = TRANSFER; + else if(psr) + next_state = PSR; + end + end + + always_ff @(posedge clk or negedge rst_n) + state <= !rst_n ? ISSUE : next_state; + +endmodule diff --git a/rtl/core/core_control_data.sv b/rtl/core/core_control_data.sv new file mode 100644 index 0000000..3174ee1 --- /dev/null +++ b/rtl/core/core_control_data.sv @@ -0,0 +1,117 @@ +`include "core/uarch.sv" + +module core_control_data +( + input logic clk, + rst_n, + + input insn_decode dec, + input word rd_value_a, + rd_value_b, + input logic mem_ready, + mem_write, + input word mem_data_rd, + q_alu, + q_shifter, + input logic c_shifter, + + input ctrl_cycle cycle, + next_cycle, + input ptr pc_visible, + input logic ldst_next, + input logic[1:0] ldst_shift, + input word mem_offset, + input psr_flags flags, + input logic exception_offset_pc, + + output alu_op alu, + output word alu_a, + alu_b, + saved_base, + output shifter_control shifter, + output word shifter_base, + output logic[7:0] shifter_shift, + output logic c_logic, + trivial_shift, + data_snd_shift_by_reg +); + + logic data_snd_is_imm; + logic[5:0] data_shift_imm; + logic[11:0] data_imm; + + assign trivial_shift = shifter_shift == 0; + + always_comb begin + if(cycle.rd_indirect_shift) + shifter_shift = rd_value_b[7:0]; + else if(cycle.transfer) + shifter_shift = {3'b000, ldst_shift, 3'b000}; + else + shifter_shift = {2'b00, data_shift_imm}; + + if(cycle.transfer) + alu_a = saved_base; + else if(cycle.exception) + alu_a = {pc_visible, 2'b00}; + else + alu_a = rd_value_a; + + if(cycle.rd_indirect_shift || cycle.with_shift) + alu_b = saved_base; + else if(cycle.transfer) + alu_b = mem_offset; + else if(data_snd_is_imm) + alu_b = {{20{1'b0}}, data_imm}; + else + alu_b = rd_value_b; + + if(cycle.transfer) + shifter_base = mem_write ? rd_value_b : mem_data_rd; + else + shifter_base = alu_b; + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + alu <= {$bits(alu){1'b0}}; + c_logic <= 0; + shifter <= {$bits(shifter){1'b0}}; + data_imm <= {$bits(data_imm){1'b0}}; + saved_base <= 0; + data_shift_imm <= {$bits(data_shift_imm){1'b0}}; + data_snd_is_imm <= 0; + data_snd_shift_by_reg <= 0; + end else if(next_cycle.issue) begin + alu <= dec.data.op; + c_logic <= 0; + + data_imm <= dec.snd.imm; + data_shift_imm <= dec.snd.shift_imm; + data_snd_is_imm <= dec.snd.is_imm; + data_snd_shift_by_reg <= dec.snd.shift_by_reg; + + shifter.shr <= dec.snd.shr; + shifter.ror <= dec.snd.ror; + shifter.put_carry <= dec.snd.put_carry; + shifter.sign_extend <= dec.snd.sign_extend; + end else if(next_cycle.rd_indirect_shift) begin + saved_base <= rd_value_b; + data_snd_shift_by_reg <= 0; + end else if(next_cycle.with_shift) begin + c_logic <= c_shifter; + saved_base <= q_shifter; + end else if(next_cycle.transfer) begin + if(ldst_next) + saved_base <= q_alu; + + shifter.ror <= 0; + shifter.shr <= !mem_write; + end else if(next_cycle.exception) begin + alu <= `ALU_SUB; + // Either pc_visible - 0 (pc + 8) or pc_visible - 4 (pc + 4) + data_imm <= {9'd0, exception_offset_pc, 2'b00}; + data_snd_is_imm <= 1; + end + +endmodule diff --git a/rtl/core/core_control_debug.sv b/rtl/core/core_control_debug.sv new file mode 100644 index 0000000..35b1334 --- /dev/null +++ b/rtl/core/core_control_debug.sv @@ -0,0 +1,25 @@ +`include "core/uarch.sv" + +module core_control_debug +( + input logic clk, + rst_n, + step, + + input ctrl_cycle next_cycle, + input logic issue, + next_bubble, + input insn_decode dec, + + output logic breakpoint +); + + logic stable, step_trigger; + + assign stable = next_cycle.issue && !dec.ctrl.nop && !next_bubble; + assign breakpoint = stable && (dec.ctrl.bkpt || step_trigger); + + always @(posedge clk or negedge rst_n) + step_trigger <= !rst_n ? 0 : step && (step_trigger || stable) && !breakpoint; + +endmodule diff --git a/rtl/core/core_control_exception.sv b/rtl/core/core_control_exception.sv new file mode 100644 index 0000000..387e9c1 --- /dev/null +++ b/rtl/core/core_control_exception.sv @@ -0,0 +1,70 @@ +`include "core/uarch.sv" + +module core_control_exception +( + input logic clk, + rst_n, + + input ctrl_cycle cycle, + next_cycle, + input insn_decode dec, + input psr_intmask intmask, + input logic issue, + irq, + high_vectors, + undefined, + prefetch_abort, + mem_fault, + + output logic escalating, + exception, + exception_offset_pc, + output psr_mode exception_mode, + output word exception_vector +); + + logic pending_irq, syscall; + logic[2:0] vector_offset; + + //TODO: fiq + + assign exception = undefined || syscall || prefetch_abort || mem_fault || pending_irq; + assign escalating = cycle.escalate; + assign exception_vector = {{16{high_vectors}}, 11'b0, vector_offset, 2'b00}; + + always @(posedge clk or negedge rst_n) + if(!rst_n) begin + syscall <= 0; + pending_irq <= 0; + vector_offset <= 0; + exception_mode <= 0; + exception_offset_pc <= 0; + end else begin + if(next_cycle.issue) begin + syscall <= issue && dec.ctrl.swi; + pending_irq <= issue && irq && !intmask.i; + end + + // A2.6.10 Exception priorities + if(mem_fault) begin + vector_offset <= 3'b100; + exception_mode <= `MODE_ABT; + end else if(pending_irq) begin + vector_offset <= 3'b110; + exception_mode <= `MODE_IRQ; + end else if(prefetch_abort) begin + vector_offset <= 3'b011; + exception_mode <= `MODE_ABT; + end else if(undefined) begin + vector_offset <= 3'b001; + exception_mode <= `MODE_UND; + end else if(syscall) begin + vector_offset <= 3'b010; + exception_mode <= `MODE_SVC; + end + + if(next_cycle.escalate) + exception_offset_pc <= !mem_fault; + end + +endmodule diff --git a/rtl/core/core_control_issue.sv b/rtl/core/core_control_issue.sv new file mode 100644 index 0000000..5bd03e1 --- /dev/null +++ b/rtl/core/core_control_issue.sv @@ -0,0 +1,80 @@ +`include "core/uarch.sv" + +module core_control_issue +( + input logic clk, + rst_n, + + input logic halt, + irq, + + input insn_decode dec, + input ptr insn_pc, + input logic issue_abort, + + input ctrl_cycle next_cycle, + input logic next_bubble, + +`ifdef VERILATOR + input word insn, +`endif + + output logic issue, + undefined, + prefetch_abort, + output ptr pc, + pc_visible, + next_pc_visible +); + + logic valid; + +`ifdef VERILATOR + word bh0 /*verilator public*/, + bh1 /*verilator public*/, + bh2 /*verilator public*/, + bh3 /*verilator public*/; +`endif + + assign valid = !next_bubble && !halt; + assign issue = next_cycle.issue && dec.ctrl.execute && valid; + assign next_pc_visible = insn_pc + 2; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + pc <= 0; + undefined <= 0; + pc_visible <= 2; + prefetch_abort <= 0; + +`ifdef VERILATOR + bh0 <= 0; + bh1 <= 0; + bh2 <= 0; + bh3 <= 0; +`endif + end else if(next_cycle.issue) begin + if(valid) begin + undefined <= dec.ctrl.undefined; + prefetch_abort <= issue_abort; + +`ifdef VERILATOR + if(dec.ctrl.undefined && !issue_abort) + $display("[core] undefined insn: [0x%08x] %08x", insn_pc << 2, insn); +`endif + end + + pc <= insn_pc; + pc_visible <= next_pc_visible; + +`ifdef VERILATOR + if(insn_pc != pc && insn_pc != pc + 1) begin + bh0 <= {pc, 2'b00}; + bh1 <= bh0; + bh2 <= bh1; + bh3 <= bh2; + end +`endif + end + +endmodule diff --git a/rtl/core/core_control_ldst.sv b/rtl/core/core_control_ldst.sv new file mode 100644 index 0000000..aa5c957 --- /dev/null +++ b/rtl/core/core_control_ldst.sv @@ -0,0 +1,129 @@ +`include "core/uarch.sv" + +module core_control_ldst +( + input logic clk, + rst_n, + + input insn_decode dec, + input logic issue, + mem_ready, + mem_ex_fail, + input word rd_value_b, + q_alu, + q_shifter, + + input ctrl_cycle cycle, + next_cycle, + input word alu_a, + alu_b, + + output ptr mem_addr, + output logic[3:0] mem_data_be, + output word mem_data_wr, + mem_offset, + output logic mem_start, + mem_write, + mem_ex_lock, + mem_user, + pop_valid, + ldst, + ldst_next, + ldst_reject, + ldst_writeback, + output logic[1:0] ldst_shift, + output word ldst_read, + strex_ok, + output reg_num popped +); + + word base; + logic block_strex, increment, pre, sign_extend; + reg_num popped_upper, popped_lower; + reg_list mem_regs, next_regs_upper, next_regs_lower; + ldst_size size; + + assign popped = increment ? popped_lower : popped_upper; + assign ldst_next = !cycle.transfer || mem_ready; + assign mem_data_wr = mem_ex_lock ? alu_b : q_shifter; + + assign strex_ok = {31'd0, mem_ex_fail || block_strex}; + assign ldst_reject = mem_ex_lock && mem_write && block_strex; + + core_control_ldst_pop pop + ( + .regs(mem_regs), + .valid(pop_valid), + .next_upper(next_regs_upper), + .next_lower(next_regs_lower), + .pop_upper(popped_upper), + .pop_lower(popped_lower) + ); + + core_control_ldst_sizes sizes + ( + .addr(mem_addr), + .read(ldst_read), + .shift(ldst_shift), + .fault(), //TODO: alignment check + .byteenable(mem_data_be), + .* + ); + + always_ff @(posedge clk or negedge rst_n) + if (!rst_n) begin + pre <= 0; + ldst <= 0; + size <= LDST_WORD; + increment <= 0; + block_strex <= 1; + sign_extend <= 0; + ldst_writeback <= 0; + + base <= {$bits(base){1'b0}}; + mem_regs <= {$bits(mem_regs){1'b0}}; + mem_user <= 0; + mem_write <= 0; + mem_start <= 0; + mem_offset <= 0; + mem_ex_lock <= 0; + end else begin + if (mem_start) + mem_start <= 0; + + if (next_cycle.issue) begin + if (issue) begin + ldst <= dec.ctrl.ldst; + mem_user <= dec.ldst.unprivileged; + end + + pre <= dec.ldst.pre_indexed; + size <= dec.ldst.size; + increment <= dec.ldst.increment; + sign_extend <= dec.ldst.sign_extend; + ldst_writeback <= dec.ldst.writeback; + + mem_regs <= dec.ldst.regs; + mem_write <= !dec.ldst.load; + mem_ex_lock <= dec.ldst.exclusive; + end else if (next_cycle.transfer) begin + if (!cycle.transfer) begin + ldst <= 0; + mem_offset <= alu_b; + end + + if (ldst_next) begin + base <= pre ? q_alu : alu_a; + mem_regs <= increment ? next_regs_lower : next_regs_upper; + end + + mem_start <= (!cycle.transfer || (mem_ready && pop_valid)) && !ldst_reject; + + if (block_strex) + block_strex <= !mem_ex_lock || mem_write; + end else if (cycle.escalate) begin + ldst <= 0; + block_strex <= 1; + end + end +endmodule diff --git a/rtl/core/core_control_ldst_pop.sv b/rtl/core/core_control_ldst_pop.sv new file mode 100644 index 0000000..64dc04d --- /dev/null +++ b/rtl/core/core_control_ldst_pop.sv @@ -0,0 +1,56 @@ +`include "core/uarch.sv" + +module core_control_ldst_pop +( + input reg_list regs, + + output logic valid, + output reg_list next_upper, + next_lower, + output reg_num pop_upper, + pop_lower +); + + assign valid = regs != 16'b0; + + always_comb begin + unique casez(regs) + 16'b???????????????1: begin pop_lower = 4'h0; next_lower = {regs[15:1], 1'b0}; end + 16'b??????????????10: begin pop_lower = 4'h1; next_lower = {regs[15:2], 2'b0}; end + 16'b?????????????100: begin pop_lower = 4'h2; next_lower = {regs[15:3], 3'b0}; end + 16'b????????????1000: begin pop_lower = 4'h3; next_lower = {regs[15:4], 4'b0}; end + 16'b???????????10000: begin pop_lower = 4'h4; next_lower = {regs[15:5], 5'b0}; end + 16'b??????????100000: begin pop_lower = 4'h5; next_lower = {regs[15:6], 6'b0}; end + 16'b?????????1000000: begin pop_lower = 4'h6; next_lower = {regs[15:7], 7'b0}; end + 16'b????????10000000: begin pop_lower = 4'h7; next_lower = {regs[15:8], 8'b0}; end + 16'b???????100000000: begin pop_lower = 4'h8; next_lower = {regs[15:9], 9'b0}; end + 16'b??????1000000000: begin pop_lower = 4'h9; next_lower = {regs[15:10], 10'b0}; end + 16'b?????10000000000: begin pop_lower = 4'ha; next_lower = {regs[15:11], 11'b0}; end + 16'b????100000000000: begin pop_lower = 4'hb; next_lower = {regs[15:12], 12'b0}; end + 16'b???1000000000000: begin pop_lower = 4'hc; next_lower = {regs[15:13], 13'b0}; end + 16'b??10000000000000: begin pop_lower = 4'hd; next_lower = {regs[15:14], 14'b0}; end + 16'b?100000000000000: begin pop_lower = 4'he; next_lower = {regs[15], 15'b0}; end + default: begin pop_lower = 4'hf; next_lower = 16'b0; end + endcase + + unique casez(regs) + 16'b1???????????????: begin pop_upper = 4'hf; next_upper = { 1'b0, regs[14:0]}; end + 16'b01??????????????: begin pop_upper = 4'he; next_upper = { 2'b0, regs[13:0]}; end + 16'b001?????????????: begin pop_upper = 4'hd; next_upper = { 3'b0, regs[12:0]}; end + 16'b0001????????????: begin pop_upper = 4'hc; next_upper = { 4'b0, regs[11:0]}; end + 16'b00001???????????: begin pop_upper = 4'hb; next_upper = { 5'b0, regs[10:0]}; end + 16'b000001??????????: begin pop_upper = 4'ha; next_upper = { 6'b0, regs[9:0]}; end + 16'b0000001?????????: begin pop_upper = 4'h9; next_upper = { 7'b0, regs[8:0]}; end + 16'b00000001????????: begin pop_upper = 4'h8; next_upper = { 8'b0, regs[7:0]}; end + 16'b000000001???????: begin pop_upper = 4'h7; next_upper = { 9'b0, regs[6:0]}; end + 16'b0000000001??????: begin pop_upper = 4'h6; next_upper = {10'b0, regs[5:0]}; end + 16'b00000000001?????: begin pop_upper = 4'h5; next_upper = {11'b0, regs[4:0]}; end + 16'b000000000001????: begin pop_upper = 4'h4; next_upper = {12'b0, regs[3:0]}; end + 16'b0000000000001???: begin pop_upper = 4'h3; next_upper = {13'b0, regs[2:0]}; end + 16'b00000000000001??: begin pop_upper = 4'h2; next_upper = {14'b0, regs[1:0]}; end + 16'b000000000000001?: begin pop_upper = 4'h1; next_upper = {15'b0, regs[0]}; end + default: begin pop_upper = 4'h0; next_upper = 16'b0; end + endcase + end + +endmodule diff --git a/rtl/core/core_control_ldst_sizes.sv b/rtl/core/core_control_ldst_sizes.sv new file mode 100644 index 0000000..dff4662 --- /dev/null +++ b/rtl/core/core_control_ldst_sizes.sv @@ -0,0 +1,46 @@ +`include "core/uarch.sv" + +module core_control_ldst_sizes +( + input word base, + q_shifter, + input ldst_size size, + input logic sign_extend, + + output ptr addr, + output word read, + output logic[1:0] shift, + output logic[3:0] byteenable, + output logic fault +); + + assign {addr, shift} = base; + + always_comb + unique case(size) + LDST_BYTE: begin + read = {{24{q_shifter[7] && sign_extend}}, q_shifter[7:0]}; + fault = 0; + + unique case(shift) + 2'b00: byteenable = 4'b0001; + 2'b01: byteenable = 4'b0010; + 2'b10: byteenable = 4'b0100; + 2'b11: byteenable = 4'b1000; + endcase + end + + LDST_HALF: begin + read = {{16{q_shifter[15] && sign_extend}}, q_shifter[15:0]}; + fault = shift[0]; + byteenable = shift[1] ? 4'b1100 : 4'b0011; + end + + LDST_WORD: begin + read = q_shifter; + fault = shift[1] || shift[0]; + byteenable = 4'b1111; + end + endcase + +endmodule diff --git a/rtl/core/core_control_mul.sv b/rtl/core/core_control_mul.sv new file mode 100644 index 0000000..8352435 --- /dev/null +++ b/rtl/core/core_control_mul.sv @@ -0,0 +1,67 @@ +`include "core/uarch.sv" + +module core_control_mul +( + input logic clk, + rst_n, + + input insn_decode dec, + input logic mul_ready, + input word rd_value_a, + rd_value_b, + + input ctrl_cycle cycle, + next_cycle, + input logic issue, + + output word mul_a, + mul_b, + mul_c_hi, + mul_c_lo, + output reg_num mul_r_add_hi, + mul_r_add_lo, + output logic mul, + mul_add, + mul_long, + mul_start, + mul_signed +); + + word hold_a, hold_b; + + assign {mul_c_hi, mul_c_lo} = {rd_value_a, rd_value_b}; + assign {mul_a, mul_b} = mul_add ? {hold_a, hold_b} : {rd_value_a, rd_value_b}; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + mul <= 0; + mul_add <= 0; + mul_long <= 0; + mul_start <= 0; + mul_signed <= 0; + mul_r_add_hi <= {$bits(mul_r_add_hi){1'b0}}; + mul_r_add_lo <= {$bits(mul_r_add_lo){1'b0}}; + + hold_a <= 0; + hold_b <= 0; + end else begin + mul_start <= 0; + + if(next_cycle.issue) begin + mul <= issue && dec.ctrl.mul; + mul_add <= dec.mul.add; + mul_long <= dec.mul.long_mul; + mul_signed <= dec.mul.signed_mul; + mul_r_add_hi <= dec.mul.r_add_hi; + mul_r_add_lo <= dec.mul.r_add_lo; + end else if(next_cycle.mul) + mul_start <= !cycle.mul; + else if(next_cycle.mul_acc_ld) begin + hold_a <= rd_value_a; + hold_b <= rd_value_b; + end + end + + //TODO: mul update_flags + +endmodule diff --git a/rtl/core/core_control_psr.sv b/rtl/core/core_control_psr.sv new file mode 100644 index 0000000..6616bc9 --- /dev/null +++ b/rtl/core/core_control_psr.sv @@ -0,0 +1,81 @@ +`include "core/uarch.sv" + +module core_control_psr +( + input logic clk, + rst_n, + + input insn_decode dec, + input word cpsr_rd, + spsr_rd, + alu_b, + input psr_mode exception_mode, + + input ctrl_cycle cycle, + next_cycle, + input logic issue, + + output logic psr, + psr_saved, + psr_write, + psr_wr_flags, + psr_wr_control, + final_psr_write, + final_restore_spsr, + output word psr_wb, + psr_wr +); + + word exception_spsr; + + assign psr_wb = psr_saved ? spsr_rd : cpsr_rd; + + always_comb begin + psr_write = 0; + + if(next_cycle.issue) + psr_write = final_psr_write || final_restore_spsr; + + if(cycle.escalate || cycle.exception) + psr_write = 1; + + if(cycle.escalate) + //TODO: F (FIQ) no cambia siempre + psr_wr = {24'b0, 3'b110, exception_mode}; + else if(cycle.exception) + psr_wr = exception_spsr; + else + psr_wr = final_restore_spsr ? spsr_rd : alu_b; + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + psr <= 0; + psr_saved <= 0; + psr_wr_flags <= 0; + psr_wr_control <= 0; + + exception_spsr <= 0; + final_psr_write <= 0; + final_restore_spsr <= 0; + end else if(next_cycle.issue) begin + psr <= issue && dec.ctrl.psr; + psr_saved <= dec.psr.saved; + psr_wr_flags <= dec.psr.wr_flags; + psr_wr_control <= dec.psr.wr_control; + + final_psr_write <= issue && dec.psr.write; + final_restore_spsr <= issue && dec.psr.restore_spsr; + end else if(next_cycle.escalate) begin + psr_saved <= 0; + psr_wr_flags <= 0; + psr_wr_control <= 1; + exception_spsr <= cpsr_rd; + end else if(next_cycle.exception) begin + psr <= 0; + psr_saved <= 1; + psr_wr_flags <= 1; + end else if(next_cycle.psr) + psr <= 0; + +endmodule diff --git a/rtl/core/core_control_select.sv b/rtl/core/core_control_select.sv new file mode 100644 index 0000000..dc04282 --- /dev/null +++ b/rtl/core/core_control_select.sv @@ -0,0 +1,80 @@ +`include "core/uarch.sv" + +module core_control_select +( + input logic clk, + rst_n, + + input insn_decode dec, + + input ctrl_cycle next_cycle, + input psr_mode mode, + input logic issue, + mem_ready, + pop_valid, + ldst_next, + input reg_num popped, + final_rd, + mul_r_add_lo, + mul_r_add_hi, + + output reg_num ra, + rb, + output psr_mode rd_mode, + wr_mode, + output logic rd_user +); + + logic wr_user; + reg_num r_shift, last_ra, last_rb; + + assign rd_mode = rd_user ? `MODE_USR : mode; + assign wr_mode = wr_user ? `MODE_USR : mode; + + always_comb begin + ra = last_ra; + rb = last_rb; + + if(next_cycle.issue) begin + ra = dec.data.rn; + rb = dec.snd.r; + end else if(next_cycle.rd_indirect_shift) + rb = r_shift; + else if(next_cycle.transfer) begin + if(ldst_next) + // final_rd viene de dec.ldst.rd + rb = pop_valid ? popped : final_rd; + end else if(next_cycle.mul_acc_ld) begin + ra = mul_r_add_hi; + rb = mul_r_add_lo; + end + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + last_ra <= {$bits(ra){1'b0}}; + last_rb <= {$bits(rb){1'b0}}; + r_shift <= {$bits(r_shift){1'b0}}; + + rd_user <= 0; + wr_user <= 0; + end else begin + last_ra <= ra; + last_rb <= rb; + + if(rd_user && next_cycle.transfer) + wr_user <= 1; + + if(rd_user && !next_cycle.transfer) + rd_user <= 0; + + if(wr_user && !next_cycle.transfer) + wr_user <= 0; + + if(next_cycle.issue) begin + r_shift <= dec.snd.r_shift; + rd_user <= issue && dec.ctrl.ldst && dec.ldst.user_regs; + end + end + +endmodule diff --git a/rtl/core/core_control_stall.sv b/rtl/core/core_control_stall.sv new file mode 100644 index 0000000..02a7552 --- /dev/null +++ b/rtl/core/core_control_stall.sv @@ -0,0 +1,42 @@ +`include "core/uarch.sv" + +module core_control_stall +( + input logic clk, + rst_n, + halt, + + input insn_decode dec, + + input ctrl_cycle next_cycle, + input logic rd_user, + final_update_flags, + final_restore_spsr, + final_psr_write, + final_writeback, + input reg_num final_rd, + + output logic halted, + stall, + bubble, + next_bubble +); + + logic pc_rd_hazard, pc_wr_hazard, rn_pc_hazard, snd_pc_hazard, psr_hazard, flags_hazard; + + assign stall = !next_cycle.issue || next_bubble || halt; + assign halted = halt && !next_bubble && next_cycle.issue; + assign next_bubble = pc_rd_hazard || pc_wr_hazard || flags_hazard || psr_hazard || rd_user; + + //FIXME: pc_rd_hazard no debería definirse sin final_writeback? + assign psr_hazard = final_psr_write || final_restore_spsr; + assign pc_rd_hazard = final_writeback && (rn_pc_hazard || snd_pc_hazard); + assign pc_wr_hazard = final_writeback && final_rd == `R15; + assign rn_pc_hazard = dec.data.uses_rn && dec.data.rn == `R15; + assign flags_hazard = dec.ctrl.conditional && final_update_flags; + assign snd_pc_hazard = !dec.snd.is_imm && dec.snd.r == `R15; + + always_ff @(posedge clk or negedge rst_n) + bubble <= !rst_n ? 0 : next_cycle.issue && next_bubble; + +endmodule diff --git a/rtl/core/core_control_writeback.sv b/rtl/core/core_control_writeback.sv new file mode 100644 index 0000000..027a7d7 --- /dev/null +++ b/rtl/core/core_control_writeback.sv @@ -0,0 +1,128 @@ +`include "core/uarch.sv" + +module core_control_writeback +( + input logic clk, + rst_n, + + input insn_decode dec, + input psr_flags alu_flags, + input word q_alu, + ldst_read, + input logic mem_ready, + mem_ex_lock, + mem_write, + input word mul_q_hi, + mul_q_lo, + strex_ok, + + input ctrl_cycle cycle, + next_cycle, + input word saved_base, + exception_vector, + psr_wb, + coproc_wb, + input reg_num ra, + popped, + mul_r_add_hi, + input logic issue, + pop_valid, + ldst_next, + ldst_reject, + + output reg_num rd, + final_rd, + output logic writeback, + final_writeback, + update_flags, + final_update_flags, + output word wr_value +); + + reg_num last_rd; + + always_comb begin + rd = last_rd; + if(next_cycle.transfer) begin + if(mem_ready) + rd = final_rd; + end else if(next_cycle.issue || next_cycle.base_writeback) + rd = final_rd; + else if(next_cycle.exception) + rd = `R15; + else if(next_cycle.mul_hi_wb) + rd = mul_r_add_hi; + + if(next_cycle.issue) + writeback = final_writeback; + else if(next_cycle.transfer) + writeback = mem_ready && !mem_write; + else if(next_cycle.base_writeback) + writeback = !mem_write; + else if(next_cycle.exception || next_cycle.mul_hi_wb) + writeback = 1; + else + writeback = 0; + + if(cycle.transfer) + wr_value = (mem_ex_lock && mem_write) ? strex_ok : ldst_read; + else if(cycle.base_writeback) + wr_value = saved_base; + else if(cycle.mul || cycle.mul_hi_wb) + wr_value = mul_q_lo; + else if(cycle.psr) + wr_value = psr_wb; + else if(cycle.coproc) + wr_value = coproc_wb; + else + // Ruta combinacional larga + wr_value = q_alu; + + if(next_cycle.transfer) begin + if(mem_ready) + wr_value = ldst_read; + end else if(next_cycle.base_writeback) + wr_value = ldst_read; + else if(next_cycle.exception) + wr_value = exception_vector; + else if(next_cycle.mul_hi_wb) + wr_value = mul_q_hi; + + update_flags = 0; + if(next_cycle.issue) + update_flags = final_update_flags; + else if(next_cycle.exception) + update_flags = 0; + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + last_rd <= 0; + final_rd <= 0; + final_writeback <= 0; + final_update_flags <= 0; + end else begin + last_rd <= rd; + + if(next_cycle.issue) + final_rd <= dec.data.rd; + else if(next_cycle.transfer) begin + if(ldst_next && pop_valid) + final_rd <= popped; + end else if(next_cycle.base_writeback) + final_rd <= ra; + else if(next_cycle.exception) + final_rd <= `R14; + + if(next_cycle.issue) + final_writeback <= issue && dec.ctrl.writeback; + else if(next_cycle.exception) + final_writeback <= 1; + + if(next_cycle.issue) + final_update_flags <= issue && dec.psr.update_flags; + else if(next_cycle.exception) + final_update_flags <= 0; + end + +endmodule diff --git a/rtl/core/core_cp15.sv b/rtl/core/core_cp15.sv new file mode 100644 index 0000000..09b899a --- /dev/null +++ b/rtl/core/core_cp15.sv @@ -0,0 +1,144 @@ +`include "core/cp15_map.sv" +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_cp15 +( + input logic clk, + rst_n, + transfer, + input coproc_decode dec, + input word write, + + input logic halt, + fault_register, + fault_page, + input ptr fault_addr, + input mmu_fault_type fault_type, + input mmu_domain fault_domain, + + output word read, + mmu_dac, + output logic high_vectors, + mmu_enable, + output mmu_base mmu_ttbr +); + + logic load; + reg_num crn, crm; + cp_opcode op1, op2; + + assign {crn, crm} = {dec.crn, dec.crm}; + assign {op1, op2} = {dec.op1, dec.op2}; + assign load = dec.load; + + word read_cpuid, read_syscfg, read_ttbr, read_domain, read_far, + read_fsr, read_cache_lockdown, read_tlb_lockdown, read_cyclecnt; + + core_cp15_cpuid cpuid + ( + .read(read_cpuid), + .* + ); + + core_cp15_syscfg syscfg + ( + .read(read_syscfg), + .transfer(transfer && crn == `CP15_CRN_SYSCFG), + .* + ); + + core_cp15_ttbr ttbr + ( + .read(read_ttbr), + .transfer(transfer && crn == `CP15_CRN_TTBR), + .* + ); + + core_cp15_domain domain + ( + .read(read_domain), + .transfer(transfer && crn == `CP15_CRN_DOMAIN), + .* + ); + + core_cp15_far far_ + ( + .read(read_far), + .transfer(transfer && crn == `CP15_CRN_FAR), + .* + ); + + core_cp15_fsr fsr + ( + .read(read_fsr), + .transfer(transfer && crn == `CP15_CRN_FSR), + .* + ); + + core_cp15_cache cache + ( + .transfer(transfer && crn == `CP15_CRN_CACHE), + .* + ); + + core_cp15_tlb tlb + ( + .transfer(transfer && crn == `CP15_CRN_TLB), + .* + ); + + core_cp15_cache_lockdown cache_lockdown + ( + .read(read_cache_lockdown), + .transfer(transfer && crn == `CP15_CRN_CACHE_LCK), + .* + ); + + core_cp15_tlb_lockdown tlb_lockdown + ( + .read(read_tlb_lockdown), + .transfer(transfer && crn == `CP15_CRN_TLB_LCK), + .* + ); + + core_cp15_cyclecnt cyclecnt + ( + .read(read_cyclecnt), + .* + ); + + always_comb + unique case(crn) + `CP15_CRN_CPUID: + read = read_cpuid; + + `CP15_CRN_SYSCFG: + read = read_syscfg; + + `CP15_CRN_TTBR: + read = read_ttbr; + + `CP15_CRN_DOMAIN: + read = read_domain; + + `CP15_CRN_FAR: + read = read_far; + + `CP15_CRN_FSR: + read = read_fsr; + + `CP15_CRN_CACHE_LCK: + read = read_cache_lockdown; + + `CP15_CRN_TLB_LCK: + read = read_tlb_lockdown; + + `CP15_CRN_CYCLECNT: + read = read_cyclecnt; + + default: + read = {$bits(read){1'bx}}; + endcase + +endmodule diff --git a/rtl/core/core_cp15_cache.sv b/rtl/core/core_cp15_cache.sv new file mode 100644 index 0000000..cb6d4ad --- /dev/null +++ b/rtl/core/core_cp15_cache.sv @@ -0,0 +1,15 @@ +`include "core/uarch.sv" + +module core_cp15_cache +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write +); + + //TODO + +endmodule diff --git a/rtl/core/core_cp15_cache_lockdown.sv b/rtl/core/core_cp15_cache_lockdown.sv new file mode 100644 index 0000000..65d4c0f --- /dev/null +++ b/rtl/core/core_cp15_cache_lockdown.sv @@ -0,0 +1,18 @@ +`include "core/uarch.sv" + +module core_cp15_cache_lockdown +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + output word read +); + + //TODO, aunque al parecer Linux no usa esto + assign read = 0; + +endmodule diff --git a/rtl/core/core_cp15_cpuid.sv b/rtl/core/core_cp15_cpuid.sv new file mode 100644 index 0000000..6e23c7e --- /dev/null +++ b/rtl/core/core_cp15_cpuid.sv @@ -0,0 +1,70 @@ +`include "core/uarch.sv" +`include "core/cp15_map.sv" + +module core_cp15_cpuid +( + input cp_opcode op2, + output word read +); + + /* ARM810.pdf, p. 104: Reading from CP15 register 0 returns + * the value 0x4101810x. + */ + cp15_cpuid_main main; + assign main.implementor = 8'h41; // 'A' (ARM) + assign main.variant = 4'h0; + assign main.architecture = 4'h1; // ARMv4 (no Thumb) + assign main.part_number = 12'h810; + assign main.revision = 4'h0; + + cp15_cpuid_cache cache; + assign cache.mbz = 3'b000; + assign cache.ctype = 4'b0001; // Write-back, range ops not supported + assign cache.s = 1; // Split instruction and data caches + assign cache.dsize = cachesize; + assign cache.isize = cachesize; + + cp15_cpuid_cache_size cachesize; + assign cachesize.p = 0; + assign cachesize.mbz = 0; + assign cachesize.size = 4'b0100; // 8KiB + assign cachesize.assoc = 3'b001; // 2-way associative + assign cachesize.m = 0; + assign cachesize.len = 2'b10; // 32-byte cache lines + + cp15_cpuid_tcm tcm; + assign tcm = 0; + + cp15_cpuid_tlb tlb; + assign tlb.sbz0 = 8'd0; + assign tlb.ilsize = 8'd0; + assign tlb.dlsize = 8'd0; + assign tlb.sbz1 = 7'd0; + assign tlb.s = 1; + + cp15_cpuid_mpu mpu; + assign mpu = 0; + + always_comb + unique case(op2) + `CP15_CPUID_CACHE: + read = cache; + + `CP15_CPUID_TCM: + read = tcm; + + `CP15_CPUID_TLB: + read = tlb; + + `CP15_CPUID_MPU: + read = mpu; + + /* If an value corresponding to an unimplemented or + * reserved ID register is encountered, the System Control + * coprocessor returns the value of the main ID register. + */ + default: + read = main; + endcase + +endmodule diff --git a/rtl/core/core_cp15_cyclecnt.sv b/rtl/core/core_cp15_cyclecnt.sv new file mode 100644 index 0000000..b079a1b --- /dev/null +++ b/rtl/core/core_cp15_cyclecnt.sv @@ -0,0 +1,23 @@ +`include "core/uarch.sv" + +module core_cp15_cyclecnt +( + input logic clk, + rst_n, + + input logic halt, + + output word read +); + + word cyclecnt; + + assign read = cyclecnt; + + always @(posedge clk or negedge rst_n) + if(!rst_n) + cyclecnt <= 0; + else if(!halt) + cyclecnt <= cyclecnt + 1; + +endmodule diff --git a/rtl/core/core_cp15_domain.sv b/rtl/core/core_cp15_domain.sv new file mode 100644 index 0000000..de37de4 --- /dev/null +++ b/rtl/core/core_cp15_domain.sv @@ -0,0 +1,24 @@ +`include "core/uarch.sv" + +module core_cp15_domain +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + output word read, + mmu_dac /*verilator public*/ +); + + assign read = mmu_dac; + + always @(posedge clk or negedge rst_n) + if(!rst_n) + mmu_dac <= 0; + else if(transfer && !load) + mmu_dac <= write; + +endmodule diff --git a/rtl/core/core_cp15_far.sv b/rtl/core/core_cp15_far.sv new file mode 100644 index 0000000..ca1dcf1 --- /dev/null +++ b/rtl/core/core_cp15_far.sv @@ -0,0 +1,31 @@ +`include "core/uarch.sv" +`include "core/cp15_map.sv" + +module core_cp15_far +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + input logic fault_register, + input ptr fault_addr, + + output word read /*verilator public*/ +); + + word far; + + assign read = far; + + always @(posedge clk or negedge rst_n) + if(!rst_n) + far <= 0; + else if(fault_register) + far <= {fault_addr, 2'b00}; + else if(transfer && !load) + far <= write; + +endmodule diff --git a/rtl/core/core_cp15_fsr.sv b/rtl/core/core_cp15_fsr.sv new file mode 100644 index 0000000..b388d00 --- /dev/null +++ b/rtl/core/core_cp15_fsr.sv @@ -0,0 +1,43 @@ +`include "core/cp15_map.sv" +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_cp15_fsr +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + input logic fault_register, + fault_page, + input mmu_fault_type fault_type, + input mmu_domain fault_domain, + + output word read /*verilator public*/ +); + + logic fsr_page; + mmu_domain fsr_domain; + mmu_fault_type fsr_type; + + assign read = {24'd0, fsr_domain, fsr_type, fsr_page, 1'b1}; + + always @(posedge clk or negedge rst_n) + if(!rst_n) begin + fsr_page <= 0; + fsr_type <= 0; + fsr_domain <= 0; + end else if(fault_register) begin + fsr_page <= fault_page; + fsr_type <= fault_type; + fsr_domain <= fault_domain; + end else if(transfer && !load) begin + fsr_page <= write[1]; + fsr_type <= write[3:2]; + fsr_domain <= write[7:4]; + end + +endmodule diff --git a/rtl/core/core_cp15_syscfg.sv b/rtl/core/core_cp15_syscfg.sv new file mode 100644 index 0000000..cdd6014 --- /dev/null +++ b/rtl/core/core_cp15_syscfg.sv @@ -0,0 +1,68 @@ +`include "core/uarch.sv" +`include "core/cp15_map.sv" + +module core_cp15_syscfg +( + input logic clk, + rst_n, + + input logic load, + transfer, + input cp_opcode op2, + input word write, + + output word read, + output logic high_vectors, + mmu_enable +); + + logic dcache_enable, icache_enable; + + cp15_syscfg_ctrl ctrl /*verilator public*/, write_ctrl; + + assign write_ctrl = write; + + always_comb begin + ctrl = {$bits(ctrl){1'b0}}; + ctrl.m = mmu_enable; + ctrl.c = dcache_enable; + ctrl.l = 1; + ctrl.d = 1; + ctrl.p = 1; + ctrl.z = 1; + ctrl.i = icache_enable; + ctrl.v = high_vectors; + ctrl.dt = 1; + ctrl.it = 1; + + unique case(op2) + `CP15_SYSCFG_CTRL: + read = ctrl; + + `CP15_SYSCFG_ACCESS: + read = 0; + + default: + read = 0; + endcase + end + + always @(posedge clk or negedge rst_n) + if(!rst_n) begin + mmu_enable <= 0; + high_vectors <= 0; + dcache_enable <= 0; + icache_enable <= 0; + end else if(transfer && !load) + unique case(op2) + `CP15_SYSCFG_CTRL: begin + mmu_enable <= write_ctrl.m; + high_vectors <= write_ctrl.v; + dcache_enable <= write_ctrl.c; + icache_enable <= write_ctrl.i; + end + + default: ; + endcase + +endmodule diff --git a/rtl/core/core_cp15_tlb.sv b/rtl/core/core_cp15_tlb.sv new file mode 100644 index 0000000..5cbd19d --- /dev/null +++ b/rtl/core/core_cp15_tlb.sv @@ -0,0 +1,15 @@ +`include "core/uarch.sv" + +module core_cp15_tlb +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write +); + + //TODO + +endmodule diff --git a/rtl/core/core_cp15_tlb_lockdown.sv b/rtl/core/core_cp15_tlb_lockdown.sv new file mode 100644 index 0000000..1972c33 --- /dev/null +++ b/rtl/core/core_cp15_tlb_lockdown.sv @@ -0,0 +1,18 @@ +`include "core/uarch.sv" + +module core_cp15_tlb_lockdown +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + output word read +); + + //TODO, aunque al parecer Linux no usa esto + assign read = 0; + +endmodule diff --git a/rtl/core/core_cp15_ttbr.sv b/rtl/core/core_cp15_ttbr.sv new file mode 100644 index 0000000..3b1a76a --- /dev/null +++ b/rtl/core/core_cp15_ttbr.sv @@ -0,0 +1,45 @@ +`include "core/cp15_map.sv" +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_cp15_ttbr +( + input logic clk, + rst_n, + + input logic load, + transfer, + input word write, + + output word read /*verilator public*/, + output mmu_base mmu_ttbr +); + + logic s, c; + cp15_ttbr read_ttbr, write_ttbr; + logic[1:0] rgn; + + assign read = read_ttbr; + assign write_ttbr = write; + + assign read_ttbr.s = s; + assign read_ttbr.c = c; + assign read_ttbr.sbz = 9'd0; + assign read_ttbr.rgn = rgn; + assign read_ttbr.imp = 0; + assign read_ttbr.base = mmu_ttbr; + + always @(posedge clk or negedge rst_n) + if(!rst_n) begin + s <= 0; + c <= 0; + rgn <= 0; + mmu_ttbr <= 0; + end else if(transfer && !load) begin + s <= write_ttbr.s; + c <= write_ttbr.c; + rgn <= write_ttbr.rgn; + mmu_ttbr <= write_ttbr.base; + end + +endmodule diff --git a/rtl/core/core_decode.sv b/rtl/core/core_decode.sv new file mode 100644 index 0000000..b43c239 --- /dev/null +++ b/rtl/core/core_decode.sv @@ -0,0 +1,195 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode +( + input word insn, + + output insn_decode dec +); + + mul_decode dec_mul; + psr_decode dec_psr; + snd_decode dec_snd; + ctrl_decode dec_ctrl; + data_decode dec_data; + ldst_decode dec_ldst; + branch_decode dec_branch; + coproc_decode dec_coproc; + + assign dec.mul = dec_mul; + assign dec.psr = dec_psr; + assign dec.snd = dec_snd; + assign dec.ctrl = dec_ctrl; + assign dec.data = dec_data; + assign dec.ldst = dec_ldst; + assign dec.branch = dec_branch; + assign dec.coproc = dec_coproc; + + assign dec_ctrl.nop = 0; + assign dec_ctrl.mul = mul; + assign dec_ctrl.swi = swi; + assign dec_ctrl.psr = psr; + assign dec_ctrl.ldst = ldst; + assign dec_ctrl.bkpt = bkpt; + assign dec_ctrl.branch = branch; + assign dec_ctrl.coproc = coproc; + assign dec_ctrl.execute = execute; + assign dec_ctrl.writeback = writeback; + assign dec_ctrl.undefined = undefined; + assign dec_ctrl.conditional = conditional; + + assign dec_psr.saved = psr_saved; + assign dec_psr.write = psr_write; + assign dec_psr.wr_flags = psr_wr_flags; + assign dec_psr.wr_control = psr_wr_control; + assign dec_psr.update_flags = update_flags; + assign dec_psr.restore_spsr = restore_spsr; + + logic execute, undefined, conditional, writeback, update_flags, + restore_spsr, branch, ldst, mul, swi, psr, coproc, bkpt, + psr_saved, psr_write, psr_wr_flags, psr_wr_control; + + core_decode_mux mux + ( + .* + ); + + logic snd_is_imm, snd_ror_if_imm, snd_shift_by_reg_if_reg, snd_undefined; + snd_decode snd; + + core_decode_snd snd_operand + ( + .decode(snd), + .is_imm(snd_is_imm), + .ror_if_imm(snd_ror_if_imm), + .shift_by_reg_if_reg(snd_shift_by_reg_if_reg), + .undefined(snd_undefined), + .* + ); + + logic branch_link; + + core_decode_branch group_branch + ( + .link(branch_link), + .offset(dec_branch.offset), + .* + ); + + data_decode data; + logic data_writeback, data_update_flags, data_restore_spsr, + data_is_imm, data_shift_by_reg_if_reg, data_conditional; + + core_decode_data group_data + ( + .decode(data), + .writeback(data_writeback), + .conditional(data_conditional), + .update_flags(data_update_flags), + .restore_spsr(data_restore_spsr), + .snd_is_imm(data_is_imm), + .snd_shift_by_reg_if_reg(data_shift_by_reg_if_reg), + .* + ); + + logic ldst_single_is_imm; + ldst_decode ldst_single; + + core_decode_ldst_single group_ldst_single + ( + .snd_is_imm(ldst_single_is_imm), + .decode(ldst_single), + .* + ); + + ldst_decode ldst_misc; + logic ldst_misc_off_is_imm; + reg_num ldst_misc_off_reg; + logic[7:0] ldst_misc_off_imm; + + core_decode_ldst_misc group_ldst_misc + ( + .decode(ldst_misc), + .off_imm(ldst_misc_off_imm), + .off_reg(ldst_misc_off_reg), + .off_is_imm(ldst_misc_off_is_imm), + .* + ); + + logic ldst_mult_restore_spsr; + ldst_decode ldst_multiple; + + core_decode_ldst_multiple group_ldst_multiple + ( + .decode(ldst_multiple), + .restore_spsr(ldst_mult_restore_spsr), + .* + ); + + reg_num ldst_ex_snd_r; + ldst_decode ldst_exclusive; + + core_decode_ldst_exclusive group_ldst_ex + ( + .snd_r(ldst_ex_snd_r), + .decode(ldst_exclusive), + .* + ); + + ldst_decode ldst_addr; + data_decode data_ldst; + + core_decode_ldst_addr ldst2data + ( + .ldst(ldst_addr), + .alu(data_ldst) + ); + + logic mul_update_flags; + reg_num mul_rd, mul_rs, mul_rm; + + core_decode_mul group_mul + ( + .decode(dec_mul), + .rd(mul_rd), + .rs(mul_rs), + .rm(mul_rm), + .update_flags(mul_update_flags), + .* + ); + + logic coproc_writeback, coproc_update_flags; + reg_num coproc_rd; + + core_decode_coproc group_coproc + ( + .rd(coproc_rd), + .decode(dec_coproc), + .writeback(coproc_writeback), + .update_flags(coproc_update_flags), + .* + ); + + logic mrs_spsr; + reg_num mrs_rd; + + core_decode_mrs group_mrs + ( + .rd(mrs_rd), + .spsr(mrs_spsr), + .* + ); + + logic msr_spsr, msr_is_imm; + msr_mask msr_fields; + + core_decode_msr group_msr + ( + .spsr(msr_spsr), + .fields(msr_fields), + .snd_is_imm(msr_is_imm), + .* + ); + +endmodule diff --git a/rtl/core/core_decode_branch.sv b/rtl/core/core_decode_branch.sv new file mode 100644 index 0000000..9916374 --- /dev/null +++ b/rtl/core/core_decode_branch.sv @@ -0,0 +1,18 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_branch +( + input word insn, + + output logic link, + output ptr offset +); + + logic[23:0] immediate; + assign immediate = insn `FIELD_B_OFFSET; + + assign link = insn `FIELD_B_L; + assign offset = {{6{immediate[23]}}, immediate}; + +endmodule diff --git a/rtl/core/core_decode_coproc.sv b/rtl/core/core_decode_coproc.sv new file mode 100644 index 0000000..c9a68c7 --- /dev/null +++ b/rtl/core/core_decode_coproc.sv @@ -0,0 +1,24 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_coproc +( + input word insn, + + output coproc_decode decode, + output reg_num rd, + output logic writeback, + update_flags +); + + assign rd = insn `FIELD_CP_RD; + assign writeback = decode.load && rd != `R15; + assign update_flags = decode.load && rd == `R15; + + assign decode.crn = insn `FIELD_CP_CRN; + assign decode.crm = insn `FIELD_CP_CRM; + assign decode.op1 = insn `FIELD_CP_OPCODE; + assign decode.op2 = insn `FIELD_CP_OPCODE2; + assign decode.load = insn `FIELD_CP_LOAD; + +endmodule diff --git a/rtl/core/core_decode_data.sv b/rtl/core/core_decode_data.sv new file mode 100644 index 0000000..a4e993e --- /dev/null +++ b/rtl/core/core_decode_data.sv @@ -0,0 +1,65 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_data +( + input word insn, + + output data_decode decode, + output logic snd_is_imm, + snd_shift_by_reg_if_reg, + writeback, + conditional, + update_flags, + restore_spsr +); + + alu_op op; + reg_num rn, rd; + logic uses_rn; + + assign decode.op = op; + assign decode.rn = rn; + assign decode.rd = rd; + assign decode.uses_rn = uses_rn; + + assign rn = insn `FIELD_DATA_RN; + assign rd = insn `FIELD_DATA_RD; + assign op = insn `FIELD_DATA_OPCODE; + + assign snd_is_imm = insn `FIELD_DATA_IMM; + assign snd_shift_by_reg_if_reg = insn `FIELD_DATA_REGSHIFT; + + always_comb begin + unique case(op) + `ALU_ADC, `ALU_SBC, `ALU_RSC: + conditional = 1; + + default: + conditional = 0; + endcase + + unique case(op) + `ALU_CMP, `ALU_CMN, `ALU_TST, `ALU_TEQ: + writeback = 0; + + default: + writeback = 1; + endcase + + unique case(op) + `ALU_MOV, `ALU_MVN: + uses_rn = 0; + + default: + uses_rn = 1; + endcase + + update_flags = insn `FIELD_DATA_S; + restore_spsr = (rd == `R15) & update_flags; + + if(restore_spsr) + update_flags = 0; + end + +endmodule diff --git a/rtl/core/core_decode_ldst_addr.sv b/rtl/core/core_decode_ldst_addr.sv new file mode 100644 index 0000000..345f0ea --- /dev/null +++ b/rtl/core/core_decode_ldst_addr.sv @@ -0,0 +1,15 @@ +`include "core/uarch.sv" + +module core_decode_ldst_addr +( + input ldst_decode ldst, + + output data_decode alu +); + + assign alu.op = ldst.increment ? `ALU_ADD : `ALU_SUB; + assign alu.rn = ldst.rn; + assign alu.rd = ldst.rd; + assign alu.uses_rn = 1; + +endmodule diff --git a/rtl/core/core_decode_ldst_exclusive.sv b/rtl/core/core_decode_ldst_exclusive.sv new file mode 100644 index 0000000..f45cbfa --- /dev/null +++ b/rtl/core/core_decode_ldst_exclusive.sv @@ -0,0 +1,27 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_ldst_exclusive +( + input word insn, + + output ldst_decode decode, + output reg_num snd_r +); + + assign snd_r = insn `FIELD_LDST_EX_R_OK; + + assign decode.rn = insn `FIELD_LDST_EX_RN; + assign decode.rd = insn `FIELD_LDST_EX_RD; + assign decode.size = LDST_WORD; + assign decode.load = insn `FIELD_LDST_EX_LD; + assign decode.increment = 0; + assign decode.writeback = 0; + assign decode.exclusive = 1; + assign decode.sign_extend = 0; + assign decode.pre_indexed = 0; + assign decode.unprivileged = 0; + assign decode.user_regs = 0; + assign decode.regs = 16'b0; + +endmodule diff --git a/rtl/core/core_decode_ldst_misc.sv b/rtl/core/core_decode_ldst_misc.sv new file mode 100644 index 0000000..bedbdf4 --- /dev/null +++ b/rtl/core/core_decode_ldst_misc.sv @@ -0,0 +1,36 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_ldst_misc +( + input word insn, + + output ldst_decode decode, + output logic off_is_imm, + output logic[7:0] off_imm, + output reg_num off_reg +); + + logic p, w; + + assign decode.rn = insn `FIELD_LDST_MISC_RN; + assign decode.rd = insn `FIELD_LDST_MISC_RD; + assign decode.size = insn `FIELD_LDST_MISC_H ? LDST_HALF : LDST_BYTE; + assign decode.load = insn `FIELD_LDST_LD; + assign decode.increment = insn `FIELD_LDST_MISC_U; + assign decode.writeback = !p || w; + assign decode.exclusive = 0; + assign decode.sign_extend = insn `FIELD_LDST_MISC_S; + assign decode.pre_indexed = p; + assign decode.unprivileged = 0; + assign decode.user_regs = 0; + assign decode.regs = 16'b0; + + assign off_imm = {insn `FIELD_LDST_MISC_IMM_HI, insn `FIELD_LDST_MISC_IMM_LO}; + assign off_reg = insn `FIELD_LDST_MISC_RM; + assign off_is_imm = insn `FIELD_LDST_MISC_IMM; + + assign p = insn `FIELD_LDST_MISC_P; + assign w = insn `FIELD_LDST_MISC_W; + +endmodule diff --git a/rtl/core/core_decode_ldst_multiple.sv b/rtl/core/core_decode_ldst_multiple.sv new file mode 100644 index 0000000..234bd56 --- /dev/null +++ b/rtl/core/core_decode_ldst_multiple.sv @@ -0,0 +1,34 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_ldst_multiple +( + input word insn, + + output ldst_decode decode, + output logic restore_spsr +); + + logic s, l; + reg_list regs; + + assign decode.rn = insn `FIELD_LDST_MULT_RN; + assign decode.rd = 4'bxxxx; + assign decode.size = LDST_WORD; + assign decode.load = l; + assign decode.increment = insn `FIELD_LDST_MULT_U; + assign decode.writeback = insn `FIELD_LDST_MULT_W; + assign decode.exclusive = 0; + assign decode.sign_extend = 0; + assign decode.pre_indexed = insn `FIELD_LDST_MULT_P; + assign decode.unprivileged = 0; + assign decode.user_regs = s && !(l && regs[`R15]); + assign decode.regs = regs; + + assign s = insn `FIELD_LDST_MULT_S; + assign l = insn `FIELD_LDST_LD; + + assign regs = insn `FIELD_LDST_MULT_LIST; + assign restore_spsr = s && l && regs[`R15]; + +endmodule diff --git a/rtl/core/core_decode_ldst_single.sv b/rtl/core/core_decode_ldst_single.sv new file mode 100644 index 0000000..0f47a30 --- /dev/null +++ b/rtl/core/core_decode_ldst_single.sv @@ -0,0 +1,31 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_ldst_single +( + input word insn, + + output ldst_decode decode, + output logic snd_is_imm +); + + logic p, w; + + assign decode.rn = insn `FIELD_LDST_SINGLE_RN; + assign decode.rd = insn `FIELD_LDST_SINGLE_RD; + assign decode.size = insn `FIELD_LDST_SINGLE_B ? LDST_BYTE : LDST_WORD; + assign decode.load = insn `FIELD_LDST_LD; + assign decode.increment = insn `FIELD_LDST_SINGLE_U; + assign decode.writeback = !p || w; + assign decode.exclusive = 0; + assign decode.sign_extend = 0; + assign decode.pre_indexed = p; + assign decode.unprivileged = !p && w; + assign decode.user_regs = 0; + assign decode.regs = 16'b0; + + assign p = insn `FIELD_LDST_SINGLE_P; + assign w = insn `FIELD_LDST_SINGLE_W; + assign snd_is_imm = !insn `FIELD_LDST_SINGLE_REG; + +endmodule diff --git a/rtl/core/core_decode_mrs.sv b/rtl/core/core_decode_mrs.sv new file mode 100644 index 0000000..8e4b19b --- /dev/null +++ b/rtl/core/core_decode_mrs.sv @@ -0,0 +1,15 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_mrs +( + input word insn, + + output reg_num rd, + output logic spsr +); + + assign rd = insn `FIELD_MRS_RD; + assign spsr = insn `FIELD_MRS_R; + +endmodule diff --git a/rtl/core/core_decode_msr.sv b/rtl/core/core_decode_msr.sv new file mode 100644 index 0000000..3f10255 --- /dev/null +++ b/rtl/core/core_decode_msr.sv @@ -0,0 +1,17 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_msr +( + input word insn, + + output msr_mask fields, + output logic spsr, + snd_is_imm +); + + assign spsr = insn `FIELD_MSR_R; + assign fields = insn `FIELD_MSR_MASK; + assign snd_is_imm = insn `FIELD_MSR_I; + +endmodule diff --git a/rtl/core/core_decode_mul.sv b/rtl/core/core_decode_mul.sv new file mode 100644 index 0000000..88cc422 --- /dev/null +++ b/rtl/core/core_decode_mul.sv @@ -0,0 +1,33 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_mul +( + input word insn, + + output mul_decode decode, + output reg_num rd, + rs, + rm, + output logic update_flags +); + + logic long_mul; + reg_num short_rd, rn; + + assign rd = long_mul ? rn : short_rd; + assign rs = insn `FIELD_MUL_RS; + assign rm = insn `FIELD_MUL_RM; + assign update_flags = insn `FIELD_MUL_S; + + assign decode.add = insn `FIELD_MUL_ACC; + assign decode.long_mul = long_mul; + assign decode.signed_mul = insn `FIELD_MUL_SIGNED; + assign decode.r_add_lo = rn; + assign decode.r_add_hi = short_rd; + + assign long_mul = insn `FIELD_MUL_LONG; + assign short_rd = insn `FIELD_MUL_RD; + assign rn = insn `FIELD_MUL_RN; + +endmodule 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: + //`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 diff --git a/rtl/core/core_decode_snd.sv b/rtl/core/core_decode_snd.sv new file mode 100644 index 0000000..3ee8722 --- /dev/null +++ b/rtl/core/core_decode_snd.sv @@ -0,0 +1,75 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_decode_snd +( + input word insn, + input logic is_imm, + ror_if_imm, + shift_by_reg_if_reg, + + output snd_decode decode, + output logic undefined +); + + reg_num r, r_shift; + logic shift_by_reg, shr, ror, put_carry, sign_extend; + logic[11:0] imm; + logic[5:0] shift_imm; + + assign decode.r = r; + assign decode.r_shift = r_shift; + assign decode.shift_by_reg = shift_by_reg; + assign decode.is_imm = is_imm; + assign decode.shr = shr; + assign decode.ror = ror; + assign decode.put_carry = put_carry; + assign decode.sign_extend = sign_extend; + assign decode.imm = imm; + assign decode.shift_imm = shift_imm; + + assign r = insn `FIELD_SND_RM; + assign r_shift = insn `FIELD_SND_RS; + assign imm = ror_if_imm ? {4'b0, insn `FIELD_SND_IMM8} : insn `FIELD_SND_IMM12; + assign shift_by_reg = ~is_imm & shift_by_reg_if_reg; + assign undefined = shift_by_reg & insn `FIELD_SND_ZEROIFREG; + + logic[1:0] shift_op; + assign shift_op = insn `FIELD_SND_SHIFT; + + always_comb begin + ror = is_imm; + shr = ~is_imm; + put_carry = 0; + sign_extend = 0; + + if(is_imm) + shift_imm = ror_if_imm ? {1'b0, insn `FIELD_SND_ROR8, 1'b0} : 6'b0; + else begin + shift_imm = {1'b0, insn `FIELD_SND_SHIFTIMM}; + + case(shift_op) + `SHIFT_LSL: shr = 0; + `SHIFT_LSR: ; + `SHIFT_ASR: sign_extend = 1; + `SHIFT_ROR: ror = 1; + endcase + + if(!shift_by_reg && shift_imm == 0) + case(shift_op) + `SHIFT_LSL: ; + + `SHIFT_LSR, `SHIFT_ASR: + shift_imm = 6'd32; + + `SHIFT_ROR: begin + // RRX + ror = 0; + shift_imm = 6'd1; + put_carry = 1; + end + endcase + end + end + +endmodule diff --git a/rtl/core/core_fetch.sv b/rtl/core/core_fetch.sv new file mode 100644 index 0000000..279d2c2 --- /dev/null +++ b/rtl/core/core_fetch.sv @@ -0,0 +1,74 @@ +`include "core/uarch.sv" + +module core_fetch +#(parameter PREFETCH_ORDER=2) +( + input logic clk, + rst_n, + stall, + fault, + fetched, + explicit_branch /*verilator public*/ /*verilator forceable*/, + wr_pc, + prefetch_flush, + input ptr branch_target, + porch_insn_pc, + input word wr_current, + fetch_data, + + output logic fetch, + flush, + nop, + output word insn, + output ptr insn_pc, + addr, + fetch_head, + output logic insn_abort +); + + ptr target /*verilator public*/ /*verilator forceable*/, hold_addr; + logic branch, prefetch_ready, fetched_valid, discard, pending, next_pending; + + assign fetch = prefetch_ready && !discard; + assign flush = branch || prefetch_flush; + assign branch = explicit_branch || wr_pc; + assign target = wr_pc ? wr_current[31:2] : branch_target; //TODO: alignment exception + assign next_pending = fetch || (pending && !fetched); + assign fetched_valid = fetched && !discard; + + core_prefetch #(.ORDER(PREFETCH_ORDER)) prefetch + ( + .head(fetch_head), + .fetched(fetched_valid), + .fetch(prefetch_ready), + .* + ); + + always_comb begin + if(branch) + fetch_head = target; + else if(prefetch_flush) + fetch_head = porch_insn_pc; + else + fetch_head = {30{1'bx}}; + + if(flush) + addr = fetch_head; + else if(fetch && fetched_valid) + addr = hold_addr + 1; + else + addr = hold_addr; + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + pending <= 0; + discard <= 0; + hold_addr <= 0; + end else begin + pending <= next_pending; + discard <= next_pending && (discard || flush); + hold_addr <= addr; + end + +endmodule diff --git a/rtl/core/core_mmu.sv b/rtl/core/core_mmu.sv new file mode 100644 index 0000000..3060d69 --- /dev/null +++ b/rtl/core/core_mmu.sv @@ -0,0 +1,140 @@ +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_mmu +( + input logic clk, + rst_n, + + input logic privileged, + mmu_enable /*verilator public*/, + input mmu_base mmu_ttbr /*verilator public*/, + input word mmu_dac, + + input logic bus_ready, + bus_ex_fail, + input word bus_data_rd, + data_data_wr, + input ptr insn_addr, + data_addr, + input logic insn_start, + data_start, + data_write, + data_ex_lock, + data_user, + input logic[3:0] data_data_be, + + output word bus_data_wr, + output logic[3:0] bus_data_be, + output ptr bus_addr, + output logic bus_start, + bus_write, + bus_ex_lock, + insn_ready, + insn_fault, + data_ready, + data_fault, + data_ex_fail, + output word insn_data_rd, + data_data_rd, + + output logic fault_register, + fault_page, + output ptr fault_addr, + output mmu_fault_type fault_type, + output mmu_domain fault_domain +); + + ptr iphys_addr, dphys_addr; + word iphys_data_rd, dphys_data_rd, dphys_data_wr; + logic[3:0] dphys_data_be; + + logic iphys_start, dphys_start, iphys_ready, dphys_ready, dphys_write, + dphys_ex_fail, dphys_ex_lock; + + assign fault_register = data_fault; + + core_mmu_pagewalk iwalk + ( + .core_addr(insn_addr), + .core_start(insn_start), + .core_write(0), + .core_ready(insn_ready), + .core_data_wr(0), + .core_data_be(0), + .core_data_rd(insn_data_rd), + .core_ex_fail(), + .core_ex_lock(0), + + .core_fault(insn_fault), + .core_fault_addr(), + .core_fault_page(), + .core_fault_type(), + .core_fault_domain(), + + .bus_addr(iphys_addr), + .bus_start(iphys_start), + .bus_write(), + .bus_ready(iphys_ready), + .bus_data_wr(), + .bus_data_be(), + .bus_data_rd(iphys_data_rd), + .bus_ex_fail(0), + .bus_ex_lock(), + + .* + ); + + core_mmu_pagewalk dwalk + ( + .core_addr(data_addr), + .core_start(data_start), + .core_write(data_write), + .core_ready(data_ready), + .core_data_wr(data_data_wr), + .core_data_be(data_data_be), + .core_data_rd(data_data_rd), + .core_ex_fail(data_ex_fail), + .core_ex_lock(data_ex_lock), + + .core_fault(data_fault), + .core_fault_addr(fault_addr), + .core_fault_page(fault_page), + .core_fault_type(fault_type), + .core_fault_domain(fault_domain), + + .bus_addr(dphys_addr), + .bus_start(dphys_start), + .bus_write(dphys_write), + .bus_ready(dphys_ready), + .bus_data_wr(dphys_data_wr), + .bus_data_be(dphys_data_be), + .bus_data_rd(dphys_data_rd), + .bus_ex_fail(dphys_ex_fail), + .bus_ex_lock(dphys_ex_lock), + + .privileged(privileged && !data_user), + .* + ); + + core_mmu_arbiter arbiter + ( + .insn_addr(iphys_addr), + .insn_start(iphys_start), + .insn_ready(iphys_ready), + .insn_data_rd(iphys_data_rd), + + .data_addr(dphys_addr), + .data_start(dphys_start), + .data_write(dphys_write), + .data_ready(dphys_ready), + .data_data_wr(dphys_data_wr), + .data_data_be(dphys_data_be), + .data_data_rd(dphys_data_rd), + .data_ex_fail(dphys_ex_fail), + .data_ex_lock(dphys_ex_lock), + + .* + ); + +endmodule diff --git a/rtl/core/core_mmu_arbiter.sv b/rtl/core/core_mmu_arbiter.sv new file mode 100644 index 0000000..b0da7c8 --- /dev/null +++ b/rtl/core/core_mmu_arbiter.sv @@ -0,0 +1,132 @@ +module core_mmu_arbiter +( + input logic clk, + rst_n, + + input logic bus_ready, + bus_ex_fail, + input word bus_data_rd, + data_data_wr, + input ptr insn_addr, + data_addr, + input logic insn_start, + data_start, + data_write, + data_ex_lock, + input logic[3:0] data_data_be, + + output word bus_data_wr, + output logic[3:0] bus_data_be, + output ptr bus_addr, + output logic bus_start, + bus_write, + bus_ex_lock, + insn_ready, + data_ready, + data_ex_fail, + output word insn_data_rd, + data_data_rd +); + + enum int unsigned + { + INSN, + DATA + } master, next_master; + + ptr hold_addr; + word hold_data_wr; + logic active, hold_ex_lock, hold_start, hold_write, hold_issue, hold_free, transition; + logic[3:0] hold_data_be; + + assign data_ex_fail = bus_ex_fail; + assign insn_data_rd = bus_data_rd; + assign data_data_rd = bus_data_rd; + + always_comb begin + next_master = master; + if(bus_ready || !active) + unique case(master) + DATA: next_master = data_start ? DATA : INSN; + INSN: next_master = !data_start && !hold_start ? INSN : DATA; + endcase + + // Causa UNOPTFLAT en Verilator con assign + transition = master != next_master; + hold_issue = transition && hold_start; + hold_free = transition || !hold_start; + + insn_ready = 0; + data_ready = 0; + + unique case(master) + INSN: insn_ready = bus_ready; + DATA: data_ready = bus_ready; + endcase + + bus_data_wr = data_data_wr; + unique case(next_master) + INSN: begin + bus_addr = insn_addr; + bus_write = 0; + bus_start = insn_start; + bus_data_be = 4'b1111; + bus_ex_lock = 0; + end + + DATA: begin + bus_addr = data_addr; + bus_write = data_write; + bus_start = data_start; + bus_data_be = data_data_be; + bus_ex_lock = data_ex_lock; + end + endcase + + if(hold_issue) begin + bus_addr = hold_addr; + bus_write = hold_write; + bus_start = 1; + bus_data_wr = hold_data_wr; + bus_data_be = hold_data_be; + bus_ex_lock = hold_ex_lock; + end + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + master <= INSN; + active <= 0; + + hold_addr <= 30'b0; + hold_start <= 0; + hold_write <= 0; + hold_data_wr <= 0; + hold_data_be <= 0; + hold_ex_lock <= 0; + end else begin + master <= next_master; + active <= bus_start || (active && !bus_ready); + + if(hold_free) + unique case(next_master) + INSN: begin + hold_addr <= data_addr; + hold_start <= data_start; + hold_write <= data_write; + hold_data_wr <= data_data_wr; + hold_data_be <= data_data_be; + hold_ex_lock <= data_ex_lock; + end + + DATA: begin + hold_addr <= insn_addr; + hold_start <= insn_start; + hold_write <= 0; + hold_data_be <= 4'b1111; + hold_ex_lock <= 0; + end + endcase + end + +endmodule diff --git a/rtl/core/core_mmu_fault.sv b/rtl/core/core_mmu_fault.sv new file mode 100644 index 0000000..ec80753 --- /dev/null +++ b/rtl/core/core_mmu_fault.sv @@ -0,0 +1,83 @@ +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_mmu_fault +( + input logic valid_entry, + skip_perms, + input word mmu_dac, + input mmu_domain domain, + input logic[1:0] ap, + input logic privileged, + write, + + output logic fault, + output mmu_fault_type fault_type +); + + mmu_domain_ctrl domain_ctrl; + + always_comb begin + unique case(domain) + 4'h0: domain_ctrl = mmu_dac[1:0]; + 4'h1: domain_ctrl = mmu_dac[3:2]; + 4'h2: domain_ctrl = mmu_dac[5:4]; + 4'h3: domain_ctrl = mmu_dac[7:6]; + 4'h4: domain_ctrl = mmu_dac[9:8]; + 4'h5: domain_ctrl = mmu_dac[11:10]; + 4'h6: domain_ctrl = mmu_dac[13:12]; + 4'h7: domain_ctrl = mmu_dac[15:14]; + 4'h8: domain_ctrl = mmu_dac[17:16]; + 4'h9: domain_ctrl = mmu_dac[19:18]; + 4'ha: domain_ctrl = mmu_dac[21:20]; + 4'hb: domain_ctrl = mmu_dac[23:22]; + 4'hc: domain_ctrl = mmu_dac[25:24]; + 4'hd: domain_ctrl = mmu_dac[27:26]; + 4'he: domain_ctrl = mmu_dac[29:28]; + 4'hf: domain_ctrl = mmu_dac[31:30]; + endcase + + fault = 0; + fault_type = `MMU_FAULT_ACCESS; + + if(!valid_entry) begin + fault = 1; + fault_type = `MMU_FAULT_WALK; + end else if(!skip_perms) begin + if(!domain_ctrl.allowed) begin + fault = 1; + fault_type = `MMU_FAULT_DOMAIN; + end else if(!domain_ctrl.manager) + /* Hay una diferencia importante entre lo que dicen los + * manuales y lo que al parecer pasa realmente. Según + * el source del kernel, 0b00 debe permitir lecturas + * desde modos privilegiados (PTE_SMALL_AP_UNO_SRO), + * lo cual corresponde al caso con S = 1 en la tabla B4-1 + * del ARM ARM. Por otro lado, el kernel nunca usa su propia + * definición de CR_S. Mi única explicación para que esto + * funcione es que los cores legacy tienen S = 1 en reset + * y a nadie nunca se le ocurrió revisar eso, o tal vez + * el manual está mal. + * + * Todo esto resulta en que, si se interpretan los bits AP + * como dice el manual de ARMv6, la página inmediatamente + * posterior a tabla de vectores altos del kernel provoque + * un prefetch abort (!!!) cuando los vectores saltan a esta, + * lo cual causa un bucle infinito de aborts a la primera IRQ. + */ + unique case(ap) + 2'b00: + fault = !privileged || write; + + 2'b01: + fault = !privileged; + + 2'b10: + fault = !privileged && write; + + 2'b11: ; + endcase + end + end + +endmodule diff --git a/rtl/core/core_mmu_pagewalk.sv b/rtl/core/core_mmu_pagewalk.sv new file mode 100644 index 0000000..bdf1989 --- /dev/null +++ b/rtl/core/core_mmu_pagewalk.sv @@ -0,0 +1,266 @@ +`include "core/mmu_format.sv" +`include "core/uarch.sv" + +module core_mmu_pagewalk +( + input logic clk, + rst_n, + + input logic privileged, + mmu_enable, + input mmu_base mmu_ttbr, + input word mmu_dac, + + input logic bus_ready, + bus_ex_fail, + input word bus_data_rd, + + input ptr core_addr, + input word core_data_wr, + input logic[3:0] core_data_be, + input logic core_start, + core_write, + core_ex_lock, + + output ptr bus_addr, + output word bus_data_wr, + output logic[3:0] bus_data_be, + output logic bus_start, + bus_write, + bus_ex_lock, + + output word core_data_rd, + output logic core_ready, + core_ex_fail, + core_fault, + core_fault_page, + output ptr core_fault_addr, + output mmu_fault_type core_fault_type, + output mmu_domain core_fault_domain +); + + enum int unsigned + { + IDLE, + L1, + L2, + DATA, + FAULT + } state; + + logic access_fault, valid_entry, skip_perms; + logic[1:0] ap, entry_type; + mmu_domain domain, entry_domain; + mmu_fault_type access_fault_type; + + assign entry_type = bus_data_rd[1:0]; + assign core_fault_domain = domain; + + core_mmu_fault access_check + ( + .write(hold_write), + .fault(access_fault), + .domain(entry_domain), + .fault_type(access_fault_type), + .* + ); + + mmu_l1_entry l1; + assign l1 = bus_data_rd; + + mmu_l1_pagetable pagetable; + assign pagetable = bus_data_rd; + + mmu_l1_section section; + assign section = bus_data_rd; + + mmu_l2_large ptentry_large; + assign ptentry_large = bus_data_rd; + + mmu_l2_small ptentry_small; + assign ptentry_small = bus_data_rd; + + mmu_l2_smallext ptentry_smallext; + assign ptentry_smallext = bus_data_rd; + + ptr target; + word hold_data; + logic hold_write, hold_ex_lock; + logic[3:0] hold_be; + + always_comb begin + ap = 2'bxx; + skip_perms = 0; + valid_entry = 1; + entry_domain = domain; + + unique case(state) + L1: + unique case(entry_type) + `MMU_L1_PAGETABLE: begin + ap = 2'bxx; + skip_perms = 1; + end + + `MMU_L1_SECTION: begin + ap = section.ap; + entry_domain = l1.domain; + end + + // Tiny (1KiB wtf?) pages and supersections not supported + default: + valid_entry = 0; + endcase + + L2: + unique case(entry_type) + `MMU_L2_FAULT: + valid_entry = 0; + + `MMU_L2_LARGE: + //TODO: ap3-ap2 (también en L2_SMALL) + ap = ptentry_large.ap0; + + `MMU_L2_SMALL: + ap = ptentry_small.ap0; + + `MMU_L2_SMALLEXT: + ap = ptentry_smallext.ap; + endcase + + default: + valid_entry = 1'bx; + endcase + end + + always @(posedge clk or negedge rst_n) + if(!rst_n) begin + state <= IDLE; + target <= 0; + domain <= 0; + + hold_be <= 0; + hold_data <= 0; + hold_write <= 0; + hold_ex_lock <= 0; + + bus_addr <= 0; + bus_start <= 0; + bus_write <= 0; + bus_ex_lock <= 0; + bus_data_be <= 0; + bus_data_wr <= 0; + + core_ready <= 0; + core_fault <= 0; + core_ex_fail <= 0; + core_data_rd <= 0; + core_fault_page <= 0; + core_fault_addr <= 0; + core_fault_type <= 0; + end else begin + if(bus_start) + bus_start <= 0; + + if(core_ready) + core_ready <= 0; + + if(core_fault) + core_fault <= 0; + + unique case(state) + IDLE: + if(core_start) begin + bus_start <= 1; + + if(mmu_enable) begin + target <= core_addr; + hold_be <= core_data_be; + hold_data <= core_data_wr; + hold_write <= core_write; + hold_ex_lock <= core_ex_lock; + + state <= L1; + bus_addr <= {mmu_ttbr, core_addr `MMU_L1_INDEX}; + bus_write <= 0; + bus_ex_lock <= 0; + end else begin + state <= DATA; + bus_addr <= core_addr; + bus_write <= core_write; + bus_ex_lock <= core_ex_lock; + bus_data_wr <= core_data_wr; + bus_data_be <= core_data_be; + end + end + + L1: + if(bus_ready) begin + domain <= l1.domain; + + unique case(entry_type) + `MMU_L1_PAGETABLE: begin + state <= L2; + bus_addr <= {pagetable.base, target `MMU_L2_INDEX}; + end + + `MMU_L1_SECTION: begin + state <= DATA; + bus_addr <= {section.base, target `MMU_SECTION_INDEX}; + bus_write <= hold_write; + bus_ex_lock <= hold_ex_lock; + bus_data_wr <= hold_data; + bus_data_be <= hold_be; + end + + default: ; + endcase + end + + L2: + if(bus_ready) begin + state <= DATA; + + bus_write <= hold_write; + bus_ex_lock <= hold_ex_lock; + bus_data_wr <= hold_data; + bus_data_be <= hold_be; + + unique case(entry_type) + `MMU_L2_FAULT: ; + + `MMU_L2_LARGE: + bus_addr <= {ptentry_large.base, target `MMU_LARGE_INDEX}; + + `MMU_L2_SMALL, `MMU_L2_SMALLEXT: + bus_addr <= {ptentry_small.base, target `MMU_SMALL_INDEX}; + endcase + end + + DATA: + if(bus_ready) begin + state <= IDLE; + core_ready <= 1; + core_ex_fail <= bus_ex_fail; + core_data_rd <= bus_data_rd; + end + + FAULT: begin + state <= IDLE; + core_fault <= 1; + core_ready <= 1; + core_fault_addr <= target; + end + endcase + + if((state == L1 || state == L2) && bus_ready) begin + if(access_fault) begin + state <= FAULT; + core_fault_type <= access_fault_type; + core_fault_page <= state == L2; + end else + bus_start <= 1; + end + end + +endmodule diff --git a/rtl/core/core_mul.sv b/rtl/core/core_mul.sv new file mode 100644 index 0000000..19bbb9a --- /dev/null +++ b/rtl/core/core_mul.sv @@ -0,0 +1,64 @@ +`include "core/uarch.sv" + +// Realiza la operación a * b + c = q +module core_mul +( + input logic clk, // clock, ya que es una máquina de estados + rst_n, + + input word a, // primer sumando + b, // segundo sumando + c_hi, // parte más significativa de c + c_lo, // parte menos significativa de c + input logic long_mul, // 1 si c es de 2 words, cualquier otro valor si c es de 1 word + add, // 1 si c se suma + sig, // 1 si a y b son signed + start, // 1 indica que se inicie la multiplicacion + + output word q_hi, // parte más significativa del resultado + q_lo, // parte menos significativa del resultado + output logic n, // no hay C ni V, ya que se dejan unaffected + z, + ready // 1 cuando la multiplicación está lista +); + + logic[1:0] wait_state; + dword c, q; + + assign ready = !start && wait_state == {$bits(wait_state){1'b0}}; + assign {q_hi, q_lo} = q; + assign n = long_mul ? q_hi[$bits(q_hi) - 1] : q_lo[$bits(q_lo) - 1]; + assign z = q_lo == 0 && (!long_mul || q_hi == 0); + + //TODO: no está probado cuantos ciclos ocupa esto una vez sintetizado + //TODO: trivio? + dsp_mul it + ( + .clock0(clk), + .aclr0(0), //TODO: parece ser active-high, así que no puede ir a rst_n + .ena0(start || !ready), + .dataa_0(a), + .datab_0(b), + .chainin(c), + .signa(sig), + .signb(sig), + .result(q) + ); + + always_comb + if(!add) + c = {$bits(c){1'b0}}; + else if(long_mul) + c = {c_hi, c_lo}; + else + c = {{$bits(word){sig && c_lo[$bits(c_lo) - 1]}}, c_lo}; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) + wait_state <= 0; + else if(wait_state > {$bits(wait_state){1'b0}}) + wait_state <= wait_state - 1; + else if(start) + wait_state <= {$bits(wait_state){1'b1}}; + +endmodule diff --git a/rtl/core/core_porch.sv b/rtl/core/core_porch.sv new file mode 100644 index 0000000..060ab91 --- /dev/null +++ b/rtl/core/core_porch.sv @@ -0,0 +1,57 @@ +`include "core/uarch.sv" + +module core_porch +( + input logic clk, + rst_n, + flush, + stall, + input psr_flags flags, + + input word fetch_insn, + input logic fetch_nop, + fetch_abort, + input ptr fetch_insn_pc, + fetch_head, + input insn_decode fetch_dec, + + output word insn, + output ptr insn_pc, + output insn_decode dec, + output logic abort +); + + logic execute, conditional, undefined, nop; + insn_decode hold_dec; + + //FIXME: User mode puede hacer msr o mcr y saltare cualquier límite de seguridad + + always_comb begin + dec = hold_dec; + dec.ctrl.nop = nop; + dec.ctrl.execute = !flush && dec.ctrl.execute && execute && !nop && !abort; + dec.ctrl.undefined = !flush && (dec.ctrl.undefined || undefined); + dec.ctrl.conditional = !flush && (dec.ctrl.conditional || conditional); + end + + core_porch_conds conds + ( + .* + ); + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + nop <= 0; // Even though it is a NOP + insn <= `NOP; + abort <= 0; + insn_pc <= 0; + hold_dec <= {$bits(hold_dec){1'b0}}; + end else if(flush || !stall) begin + nop <= flush ? 1 : fetch_nop; + insn <= flush ? `NOP : fetch_insn; + abort <= flush ? 0 : fetch_abort; + insn_pc <= flush ? fetch_head : fetch_insn_pc; + hold_dec <= fetch_dec; + end + +endmodule diff --git a/rtl/core/core_porch_conds.sv b/rtl/core/core_porch_conds.sv new file mode 100644 index 0000000..3d00e12 --- /dev/null +++ b/rtl/core/core_porch_conds.sv @@ -0,0 +1,47 @@ +`include "core/isa.sv" +`include "core/uarch.sv" + +module core_porch_conds +( + input word insn, + input psr_flags flags, + + output logic execute, + conditional, + undefined +); + + always_comb begin + undefined = 0; + conditional = 1; + + unique case(insn `FIELD_COND) + `COND_EQ: execute = flags.z; + `COND_NE: execute = ~flags.z; + `COND_HS: execute = flags.c; + `COND_LO: execute = ~flags.c; + `COND_MI: execute = flags.n; + `COND_PL: execute = ~flags.n; + `COND_VS: execute = flags.v; + `COND_VC: execute = ~flags.v; + `COND_HI: execute = flags.c & ~flags.z; + `COND_LS: execute = ~flags.c | flags.z; + `COND_GE: execute = flags.n ~^ flags.v; + `COND_LT: execute = flags.n ^ flags.v; + `COND_GT: execute = ~flags.z & (flags.n ~^ flags.v); + `COND_LE: execute = flags.z | (flags.n ^ flags.v); + + `COND_AL: begin + execute = 1; + conditional = 0; + end + + `COND_UD: begin + execute = 1'bx; + conditional = 1'bx; + undefined = 1; + end + endcase + end + +endmodule diff --git a/rtl/core/core_prefetch.sv b/rtl/core/core_prefetch.sv new file mode 100644 index 0000000..719ad95 --- /dev/null +++ b/rtl/core/core_prefetch.sv @@ -0,0 +1,84 @@ +`include "core/uarch.sv" + +module core_prefetch +#(parameter ORDER=2) +( + input logic clk, + rst_n, + stall, + flush, + fault, + fetched, + input word fetch_data, + input ptr head, + + output word insn, + output ptr insn_pc, + output logic fetch, + nop, + insn_abort +); + + localparam SIZE = (1 << ORDER) - 1; + + ptr next_pc; + logic faults[SIZE]; + logic[31:0] prefetch[SIZE]; + logic[ORDER - 1:0] valid; + + assign nop = flush ? 1 : ~|valid; + assign insn = flush ? `NOP : prefetch[0]; + assign fetch = !stall || ~&valid; + assign next_pc = ~stall & |valid ? insn_pc + 1 : insn_pc; + assign insn_abort = flush ? 0 : faults[0]; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + valid <= 0; + insn_pc <= 0; + + faults[SIZE - 1] <= 0; + prefetch[SIZE - 1] <= `NOP; + end else begin + insn_pc <= flush ? head : next_pc; + + if(flush) begin + faults[SIZE - 1] <= 0; + prefetch[SIZE - 1] <= `NOP; + end else if(fetched && valid == SIZE - 1 + {{(ORDER - 1){1'b0}}, !stall}) begin + faults[SIZE - 1] <= fault; + prefetch[SIZE - 1] <= fetch_data; + end else if(!stall) begin + faults[SIZE - 1] <= 0; + prefetch[SIZE - 1] <= `NOP; + end + + if(flush) + valid <= 0; + else if(fetched & ((stall & ~&valid) | ~|valid)) + valid <= valid + 1; + else if(~stall & ~fetched & |valid) + valid <= valid - 1; + end + + genvar i; + generate + for(i = 0; i < SIZE - 1; ++i) begin: prefetch_slots + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + faults[i] <= 0; + prefetch[i] <= `NOP; + end else if(flush) begin + faults[i] <= 0; + prefetch[i] <= `NOP; + end else if(fetched & (~(|i | |valid) | (valid == i + {{(ORDER - 1){1'b0}}, ~stall}))) begin + faults[i] <= fault; + prefetch[i] <= fetch_data; + end else if(~stall) begin + faults[i] <= faults[i + 1]; + prefetch[i] <= prefetch[i + 1]; + end + end + endgenerate + +endmodule diff --git a/rtl/core/core_psr.sv b/rtl/core/core_psr.sv new file mode 100644 index 0000000..7bbffe6 --- /dev/null +++ b/rtl/core/core_psr.sv @@ -0,0 +1,172 @@ +`include "core/uarch.sv" + +module core_psr +( + input logic clk, + rst_n, + write, + saved, + wr_flags, + wr_control, + escalating, + update_flags, + alu_v_valid, + input psr_flags alu_flags, + input word psr_wr, + + output psr_flags flags, + output psr_intmask mask, + output psr_mode mode, + output word cpsr_rd, + spsr_rd, + output logic privileged +); + + typedef struct packed + { + psr_flags flags; + psr_intmask mask; + psr_mode mode; + } psr_state; + + typedef struct packed + { + psr_flags nzcv; + logic q; + logic[1:0] reserved0; + logic j; + logic[3:0] reserved1, + ge; + logic[5:0] reserved2; + logic e; + logic a; + psr_intmask if_; + logic t; + psr_mode m; + } psr_word; + + psr_word cpsr_word /*verilator public*/, spsr_word, wr_word; + psr_flags next_flags; + psr_state cpsr, spsr, spsr_svc, spsr_abt, spsr_und, spsr_irq, spsr_fiq, + wr_state, wr_clean; + + assign mode = cpsr.mode; + assign mask = cpsr.mask; + assign flags = cpsr.flags; + assign wr_word = psr_wr; + assign cpsr_rd = cpsr_word; + assign spsr_rd = spsr_word; + assign privileged = |mode[3:0]; // Not user + assign {wr_state.flags, wr_state.mask, wr_state.mode} = {wr_word.nzcv, wr_word.if_, wr_word.m}; + +`ifdef VERILATOR + psr_word spsr_svc_word /*verilator public*/, + spsr_abt_word /*verilator public*/, + spsr_und_word /*verilator public*/, + spsr_fiq_word /*verilator public*/, + spsr_irq_word /*verilator public*/; + + always_comb begin + spsr_svc_word = {$bits(spsr_svc_word){1'b0}}; + spsr_abt_word = {$bits(spsr_abt_word){1'b0}}; + spsr_und_word = {$bits(spsr_und_word){1'b0}}; + spsr_irq_word = {$bits(spsr_irq_word){1'b0}}; + spsr_fiq_word = {$bits(spsr_fiq_word){1'b0}}; + + spsr_svc_word.a = 1; + spsr_abt_word.a = 1; + spsr_und_word.a = 1; + spsr_irq_word.a = 1; + spsr_fiq_word.a = 1; + + {spsr_svc_word.nzcv, spsr_svc_word.if_, spsr_svc_word.m} + = {spsr_svc.flags, spsr_svc.mask, spsr_svc.mode}; + + {spsr_abt_word.nzcv, spsr_abt_word.if_, spsr_abt_word.m} + = {spsr_abt.flags, spsr_abt.mask, spsr_abt.mode}; + + {spsr_und_word.nzcv, spsr_und_word.if_, spsr_und_word.m} + = {spsr_und.flags, spsr_und.mask, spsr_und.mode}; + + {spsr_irq_word.nzcv, spsr_irq_word.if_, spsr_irq_word.m} + = {spsr_irq.flags, spsr_irq.mask, spsr_irq.mode}; + + {spsr_fiq_word.nzcv, spsr_fiq_word.if_, spsr_fiq_word.m} + = {spsr_fiq.flags, spsr_fiq.mask, spsr_fiq.mode}; + end +`endif + + always_comb begin + next_flags = alu_flags; + if(!alu_v_valid) + next_flags.v = flags.v; + + unique case(mode) + `MODE_SVC: spsr = spsr_svc; + `MODE_ABT: spsr = spsr_abt; + `MODE_UND: spsr = spsr_und; + `MODE_IRQ: spsr = spsr_irq; + `MODE_FIQ: spsr = spsr_fiq; + default: spsr = cpsr; + endcase + + cpsr_word = {$bits(cpsr_word){1'b0}}; + spsr_word = {$bits(spsr_word){1'b0}}; + {cpsr_word.a, spsr_word.a} = 2'b11; + + {cpsr_word.nzcv, cpsr_word.if_, cpsr_word.m} = {flags, mask, mode}; + {spsr_word.nzcv, spsr_word.if_, spsr_word.m} = {spsr.flags, spsr.mask, spsr.mode}; + + wr_clean = wr_state; + unique case(wr_state.mode) + `MODE_USR, `MODE_FIQ, `MODE_IRQ, `MODE_SVC, + `MODE_ABT, `MODE_UND, `MODE_SYS: ; + + default: + wr_clean.mode = mode; + endcase + + if(!wr_flags) + wr_clean.flags = flags; + + if(!wr_control) begin + wr_clean.mask = mask; + wr_clean.mode = mode; + end + + if(mode == `MODE_USR && !escalating) begin + wr_clean.mask = mask; + wr_clean.mode = `MODE_USR; + end + end + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + cpsr.mode <= `MODE_SVC; + cpsr.flags <= 4'b0000; + cpsr.mask.i <= 1; + cpsr.mask.f <= 1; + + spsr_svc <= {$bits(spsr_svc){1'b0}}; + spsr_abt <= {$bits(spsr_svc){1'b0}}; + spsr_und <= {$bits(spsr_svc){1'b0}}; + spsr_irq <= {$bits(spsr_svc){1'b0}}; + spsr_fiq <= {$bits(spsr_svc){1'b0}}; + end else begin + if(!write) begin + if(update_flags) + cpsr.flags <= next_flags; + end else if(!saved) + cpsr <= wr_clean; + else + unique case(mode) + `MODE_SVC: spsr_svc <= wr_clean; + `MODE_ABT: spsr_abt <= wr_clean; + `MODE_UND: spsr_und <= wr_clean; + `MODE_IRQ: spsr_irq <= wr_clean; + `MODE_FIQ: spsr_fiq <= wr_clean; + default: ; + endcase + end + +endmodule diff --git a/rtl/core/core_reg_file.sv b/rtl/core/core_reg_file.sv new file mode 100644 index 0000000..2ba95e8 --- /dev/null +++ b/rtl/core/core_reg_file.sv @@ -0,0 +1,51 @@ +`include "core/uarch.sv" + +module core_reg_file +( + input logic clk, + rst_n, + + input psr_mode rd_mode, + input reg_num rd_r, + input reg_index wr_index, + input logic wr_enable, + wr_enable_file, + input word wr_value, + wr_current, + pc_word, + + output word rd_value +); + + // Ver comentario en uarch.sv + word file[`NUM_GPREGS] /*verilator public*/; + word rd_actual; + logic rd_pc, hold_rd_pc, forward; + reg_index rd_index; + + core_reg_map map_rd + ( + .r(rd_r), + .mode(rd_mode), + .is_pc(rd_pc), + .index(rd_index) + ); + + assign rd_value = hold_rd_pc ? pc_word : forward ? wr_current : rd_actual; + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + forward <= 0; + rd_actual <= 0; + hold_rd_pc <= 0; + end else begin + forward <= wr_enable && rd_index == wr_index; + hold_rd_pc <= rd_pc; + + if(wr_enable_file) + file[wr_index] <= wr_value; + + rd_actual <= file[rd_index]; + end + +endmodule diff --git a/rtl/core/core_reg_map.sv b/rtl/core/core_reg_map.sv new file mode 100644 index 0000000..11085d4 --- /dev/null +++ b/rtl/core/core_reg_map.sv @@ -0,0 +1,30 @@ +`include "core/uarch.sv" + +module core_reg_map +( + input reg_num r, + input psr_mode mode, + output logic is_pc, + output reg_index index +); + + reg_index usr; + assign usr = {1'b0, r}; + + always_comb begin + index = 5'bxxxxx; + is_pc = r == `R15; + + if(~is_pc) + unique case(mode) + `MODE_USR, `MODE_SYS: index = usr; + `MODE_FIQ: index = r >= 8 ? usr + 7 : usr; + `MODE_IRQ: index = r >= 13 ? usr + 9 : usr; + `MODE_UND: index = r >= 13 ? usr + 11 : usr; + `MODE_ABT: index = r >= 13 ? usr + 13 : usr; + `MODE_SVC: index = r >= 13 ? usr + 15 : usr; + default: ; + endcase + end + +endmodule diff --git a/rtl/core/core_regs.sv b/rtl/core/core_regs.sv new file mode 100644 index 0000000..f9cecad --- /dev/null +++ b/rtl/core/core_regs.sv @@ -0,0 +1,69 @@ +`include "core/uarch.sv" + +module core_regs +( + input logic clk, + rst_n, + + input reg_num rd_r_a, + rd_r_b, + wr_r, + input psr_mode rd_mode, + wr_mode, + input logic wr_enable, + input word wr_value, + input ptr pc_visible, + + output word rd_value_a, + rd_value_b, + wr_current, + output logic branch +); + + /* Las Cyclone V no tienen bloques de memoria con al menos dos puertos de + * lectura y uno de escritura (tres puertos), lo más que tienen son bloques + * de dos puertos en total. Podemos ponerle cinta a esto con dos copias + * sincronizadas del archivo de registros. + */ + + word pc_word; + logic wr_pc, wr_enable_file; + reg_index wr_index; + + assign pc_word = {pc_visible, 2'b00}; + assign wr_enable_file = wr_enable && !wr_pc; + + core_reg_file a + ( + .rd_r(rd_r_a), + .rd_value(rd_value_a), + .* + ); + + core_reg_file b + ( + .rd_r(rd_r_b), + .rd_value(rd_value_b), + .* + ); + + core_reg_map map_wr + ( + .r(wr_r), + .mode(wr_mode), + .is_pc(wr_pc), + .index(wr_index) + ); + + always_ff @(posedge clk or negedge rst_n) + if(!rst_n) begin + branch <= 0; + wr_current <= 0; + end else begin + if(wr_enable) + wr_current <= wr_value; + + branch <= wr_enable && wr_pc; + end + +endmodule diff --git a/rtl/core/core_shifter.sv b/rtl/core/core_shifter.sv new file mode 100644 index 0000000..96b8866 --- /dev/null +++ b/rtl/core/core_shifter.sv @@ -0,0 +1,42 @@ +`include "core/uarch.sv" + +module core_shifter +#(parameter W=16) +( + input shifter_control ctrl, + input logic[W - 1:0] base, + input logic[7:0] shift, + input logic c_in, + + output logic[W - 1:0] q, + output logic c +); + + localparam LOG = $clog2(W); + + logic[W - 1:0] q_no_c, q_shl, q_shr, q_ror; + logic[W:0] sign_mask; + logic c_shl, c_shr, c_ror; + + assign sign_mask = {(W + 1){ctrl.sign_extend & base[W - 1]}}; + assign {c_shl, q_shl} = {c_in, base} << shift; + assign {q_shr, c_shr} = {base, c_in} >> shift | (sign_mask & ~(sign_mask >> shift)); + + logic ror_cycle; + logic[LOG - 1:0] ror_shift; + logic[2 * W:0] ror_out; + + assign ror_shift = shift[LOG - 1:0]; + assign ror_cycle = |shift[7:LOG] & ~|ror_shift; + assign ror_out = {base, base, c_in} >> {ror_cycle, ror_shift}; + assign {q_ror, c_ror} = ror_out[W:0]; + + always_comb + if(ctrl.ror) + {c, q} = {c_ror, q_ror}; + else if(ctrl.shr) + {c, q} = {c_shr, q_shr[W - 1] | (ctrl.put_carry && c_in && shift != 0), q_shr[W - 2:0]}; + else + {c, q} = {c_shl, q_shl}; + +endmodule diff --git a/rtl/core/cp15/cache_lockdown.sv b/rtl/core/cp15/cache_lockdown.sv deleted file mode 100644 index 65d4c0f..0000000 --- a/rtl/core/cp15/cache_lockdown.sv +++ /dev/null @@ -1,18 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_cache_lockdown -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - output word read -); - - //TODO, aunque al parecer Linux no usa esto - assign read = 0; - -endmodule diff --git a/rtl/core/cp15/cache_ops.sv b/rtl/core/cp15/cache_ops.sv deleted file mode 100644 index cb6d4ad..0000000 --- a/rtl/core/cp15/cache_ops.sv +++ /dev/null @@ -1,15 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_cache -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write -); - - //TODO - -endmodule diff --git a/rtl/core/cp15/cp15.sv b/rtl/core/cp15/cp15.sv deleted file mode 100644 index 5a482d4..0000000 --- a/rtl/core/cp15/cp15.sv +++ /dev/null @@ -1,144 +0,0 @@ -`include "core/cp15/map.sv" -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_cp15 -( - input logic clk, - rst_n, - transfer, - input coproc_decode dec, - input word write, - - input logic halt, - fault_register, - fault_page, - input ptr fault_addr, - input mmu_fault_type fault_type, - input mmu_domain fault_domain, - - output word read, - mmu_dac, - output logic high_vectors, - mmu_enable, - output mmu_base mmu_ttbr -); - - logic load; - reg_num crn, crm; - cp_opcode op1, op2; - - assign {crn, crm} = {dec.crn, dec.crm}; - assign {op1, op2} = {dec.op1, dec.op2}; - assign load = dec.load; - - word read_cpuid, read_syscfg, read_ttbr, read_domain, read_far, - read_fsr, read_cache_lockdown, read_tlb_lockdown, read_cyclecnt; - - core_cp15_cpuid cpuid - ( - .read(read_cpuid), - .* - ); - - core_cp15_syscfg syscfg - ( - .read(read_syscfg), - .transfer(transfer && crn == `CP15_CRN_SYSCFG), - .* - ); - - core_cp15_ttbr ttbr - ( - .read(read_ttbr), - .transfer(transfer && crn == `CP15_CRN_TTBR), - .* - ); - - core_cp15_domain domain - ( - .read(read_domain), - .transfer(transfer && crn == `CP15_CRN_DOMAIN), - .* - ); - - core_cp15_far far_ - ( - .read(read_far), - .transfer(transfer && crn == `CP15_CRN_FAR), - .* - ); - - core_cp15_fsr fsr - ( - .read(read_fsr), - .transfer(transfer && crn == `CP15_CRN_FSR), - .* - ); - - core_cp15_cache cache - ( - .transfer(transfer && crn == `CP15_CRN_CACHE), - .* - ); - - core_cp15_tlb tlb - ( - .transfer(transfer && crn == `CP15_CRN_TLB), - .* - ); - - core_cp15_cache_lockdown cache_lockdown - ( - .read(read_cache_lockdown), - .transfer(transfer && crn == `CP15_CRN_CACHE_LCK), - .* - ); - - core_cp15_tlb_lockdown tlb_lockdown - ( - .read(read_tlb_lockdown), - .transfer(transfer && crn == `CP15_CRN_TLB_LCK), - .* - ); - - core_cp15_cyclecnt cyclecnt - ( - .read(read_cyclecnt), - .* - ); - - always_comb - unique case(crn) - `CP15_CRN_CPUID: - read = read_cpuid; - - `CP15_CRN_SYSCFG: - read = read_syscfg; - - `CP15_CRN_TTBR: - read = read_ttbr; - - `CP15_CRN_DOMAIN: - read = read_domain; - - `CP15_CRN_FAR: - read = read_far; - - `CP15_CRN_FSR: - read = read_fsr; - - `CP15_CRN_CACHE_LCK: - read = read_cache_lockdown; - - `CP15_CRN_TLB_LCK: - read = read_tlb_lockdown; - - `CP15_CRN_CYCLECNT: - read = read_cyclecnt; - - default: - read = {$bits(read){1'bx}}; - endcase - -endmodule diff --git a/rtl/core/cp15/cpuid.sv b/rtl/core/cp15/cpuid.sv deleted file mode 100644 index c9cab59..0000000 --- a/rtl/core/cp15/cpuid.sv +++ /dev/null @@ -1,70 +0,0 @@ -`include "core/uarch.sv" -`include "core/cp15/map.sv" - -module core_cp15_cpuid -( - input cp_opcode op2, - output word read -); - - /* ARM810.pdf, p. 104: Reading from CP15 register 0 returns - * the value 0x4101810x. - */ - cp15_cpuid_main main; - assign main.implementor = 8'h41; // 'A' (ARM) - assign main.variant = 4'h0; - assign main.architecture = 4'h1; // ARMv4 (no Thumb) - assign main.part_number = 12'h810; - assign main.revision = 4'h0; - - cp15_cpuid_cache cache; - assign cache.mbz = 3'b000; - assign cache.ctype = 4'b0001; // Write-back, range ops not supported - assign cache.s = 1; // Split instruction and data caches - assign cache.dsize = cachesize; - assign cache.isize = cachesize; - - cp15_cpuid_cache_size cachesize; - assign cachesize.p = 0; - assign cachesize.mbz = 0; - assign cachesize.size = 4'b0100; // 8KiB - assign cachesize.assoc = 3'b001; // 2-way associative - assign cachesize.m = 0; - assign cachesize.len = 2'b10; // 32-byte cache lines - - cp15_cpuid_tcm tcm; - assign tcm = 0; - - cp15_cpuid_tlb tlb; - assign tlb.sbz0 = 8'd0; - assign tlb.ilsize = 8'd0; - assign tlb.dlsize = 8'd0; - assign tlb.sbz1 = 7'd0; - assign tlb.s = 1; - - cp15_cpuid_mpu mpu; - assign mpu = 0; - - always_comb - unique case(op2) - `CP15_CPUID_CACHE: - read = cache; - - `CP15_CPUID_TCM: - read = tcm; - - `CP15_CPUID_TLB: - read = tlb; - - `CP15_CPUID_MPU: - read = mpu; - - /* If an value corresponding to an unimplemented or - * reserved ID register is encountered, the System Control - * coprocessor returns the value of the main ID register. - */ - default: - read = main; - endcase - -endmodule diff --git a/rtl/core/cp15/cyclecnt.sv b/rtl/core/cp15/cyclecnt.sv deleted file mode 100644 index b079a1b..0000000 --- a/rtl/core/cp15/cyclecnt.sv +++ /dev/null @@ -1,23 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_cyclecnt -( - input logic clk, - rst_n, - - input logic halt, - - output word read -); - - word cyclecnt; - - assign read = cyclecnt; - - always @(posedge clk or negedge rst_n) - if(!rst_n) - cyclecnt <= 0; - else if(!halt) - cyclecnt <= cyclecnt + 1; - -endmodule diff --git a/rtl/core/cp15/domain.sv b/rtl/core/cp15/domain.sv deleted file mode 100644 index de37de4..0000000 --- a/rtl/core/cp15/domain.sv +++ /dev/null @@ -1,24 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_domain -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - output word read, - mmu_dac /*verilator public*/ -); - - assign read = mmu_dac; - - always @(posedge clk or negedge rst_n) - if(!rst_n) - mmu_dac <= 0; - else if(transfer && !load) - mmu_dac <= write; - -endmodule diff --git a/rtl/core/cp15/far.sv b/rtl/core/cp15/far.sv deleted file mode 100644 index 36e76db..0000000 --- a/rtl/core/cp15/far.sv +++ /dev/null @@ -1,31 +0,0 @@ -`include "core/uarch.sv" -`include "core/cp15/map.sv" - -module core_cp15_far -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - input logic fault_register, - input ptr fault_addr, - - output word read /*verilator public*/ -); - - word far; - - assign read = far; - - always @(posedge clk or negedge rst_n) - if(!rst_n) - far <= 0; - else if(fault_register) - far <= {fault_addr, 2'b00}; - else if(transfer && !load) - far <= write; - -endmodule diff --git a/rtl/core/cp15/fsr.sv b/rtl/core/cp15/fsr.sv deleted file mode 100644 index 81b4992..0000000 --- a/rtl/core/cp15/fsr.sv +++ /dev/null @@ -1,43 +0,0 @@ -`include "core/cp15/map.sv" -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_cp15_fsr -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - input logic fault_register, - fault_page, - input mmu_fault_type fault_type, - input mmu_domain fault_domain, - - output word read /*verilator public*/ -); - - logic fsr_page; - mmu_domain fsr_domain; - mmu_fault_type fsr_type; - - assign read = {24'd0, fsr_domain, fsr_type, fsr_page, 1'b1}; - - always @(posedge clk or negedge rst_n) - if(!rst_n) begin - fsr_page <= 0; - fsr_type <= 0; - fsr_domain <= 0; - end else if(fault_register) begin - fsr_page <= fault_page; - fsr_type <= fault_type; - fsr_domain <= fault_domain; - end else if(transfer && !load) begin - fsr_page <= write[1]; - fsr_type <= write[3:2]; - fsr_domain <= write[7:4]; - end - -endmodule diff --git a/rtl/core/cp15/map.sv b/rtl/core/cp15/map.sv deleted file mode 100644 index 438a5bf..0000000 --- a/rtl/core/cp15/map.sv +++ /dev/null @@ -1,127 +0,0 @@ -`ifndef CORE_CP15_MAP_SV -`define CORE_CP15_MAP_SV - -`define CP15_CRN_CPUID 4'd0 -`define CP15_CRN_SYSCFG 4'd1 -`define CP15_CRN_TTBR 4'd2 -`define CP15_CRN_DOMAIN 4'd3 -`define CP15_CRN_FSR 4'd5 -`define CP15_CRN_FAR 4'd6 -`define CP15_CRN_CACHE 4'd7 -`define CP15_CRN_TLB 4'd8 -`define CP15_CRN_CACHE_LCK 4'd9 -`define CP15_CRN_TLB_LCK 4'd10 -`define CP15_CRN_DMA 4'd11 -`define CP15_CRN_PID 4'd13 -`define CP15_CRN_CYCLECNT 4'd15 - -typedef struct packed -{ - logic[31:24] implementor; - logic[23:20] variant; - logic[19:16] architecture; - logic[15:4] part_number; - logic[3:0] revision; -} cp15_cpuid_main; - -`define CP15_CPUID_CACHE 3'b001 - -typedef struct packed -{ - logic[11:11] p; - logic[10:10] mbz; - logic[9:6] size; - logic[5:3] assoc; - logic[2:2] m; - logic[1:0] len; -} cp15_cpuid_cache_size; - -typedef struct packed -{ - logic[31:29] mbz; - logic[28:25] ctype; - logic[24:24] s; - cp15_cpuid_cache_size dsize, - isize; -} cp15_cpuid_cache; - -`define CP15_CPUID_TCM 3'b010 - -typedef struct packed -{ - logic[31:29] mbz; - logic[28:19] sbz0; - logic[18:16] dtcm; - logic[15:3] sbz1; - logic[2:0] itcm; -} cp15_cpuid_tcm; - -`define CP15_CPUID_TLB 3'b011 - -typedef struct packed -{ - logic[31:24] sbz0; - logic[23:16] ilsize; - logic[15:8] dlsize; - logic[7:1] sbz1; - logic[0:0] s; -} cp15_cpuid_tlb; - -`define CP15_CPUID_MPU 3'b100 - -typedef struct packed -{ - logic[31:24] sbz0; - logic[23:16] iregion; - logic[15:8] dregion; - logic[7:1] sbz1; - logic[0:0] s; -} cp15_cpuid_mpu; - -`define CP15_SYSCFG_CTRL 3'b000 - -typedef struct packed -{ - logic[31:27] reserved; - logic[26:26] l2; - logic[25:25] ee; - logic[24:24] ve; - logic[23:23] xp; - logic[22:22] u; - logic[21:21] fi; - logic[20:20] st; - logic[19:19] sbz0; - logic[18:18] it; - logic[17:17] sbz1; - logic[16:16] dt; - logic[15:15] l4; - logic[14:14] rr; - logic[13:13] v; - logic[12:12] i; - logic[11:11] z; - logic[10:10] f; - logic[9:9] r; - logic[8:8] s; - logic[7:7] b; - logic[6:6] l; - logic[5:5] d; - logic[4:4] p; - logic[3:3] w; - logic[2:2] c; - logic[1:1] a; - logic[0:0] m; -} cp15_syscfg_ctrl; - -`define CP15_SYSCFG_ACCESS 3'b010 - -typedef struct packed -{ - logic[31:14] base; - logic[13:5] sbz; - logic[4:3] rgn; - logic[2:2] imp; - logic[1:1] s; - logic[0:0] c; -} cp15_ttbr; - -`endif diff --git a/rtl/core/cp15/syscfg.sv b/rtl/core/cp15/syscfg.sv deleted file mode 100644 index 5bd2530..0000000 --- a/rtl/core/cp15/syscfg.sv +++ /dev/null @@ -1,68 +0,0 @@ -`include "core/uarch.sv" -`include "core/cp15/map.sv" - -module core_cp15_syscfg -( - input logic clk, - rst_n, - - input logic load, - transfer, - input cp_opcode op2, - input word write, - - output word read, - output logic high_vectors, - mmu_enable -); - - logic dcache_enable, icache_enable; - - cp15_syscfg_ctrl ctrl /*verilator public*/, write_ctrl; - - assign write_ctrl = write; - - always_comb begin - ctrl = {$bits(ctrl){1'b0}}; - ctrl.m = mmu_enable; - ctrl.c = dcache_enable; - ctrl.l = 1; - ctrl.d = 1; - ctrl.p = 1; - ctrl.z = 1; - ctrl.i = icache_enable; - ctrl.v = high_vectors; - ctrl.dt = 1; - ctrl.it = 1; - - unique case(op2) - `CP15_SYSCFG_CTRL: - read = ctrl; - - `CP15_SYSCFG_ACCESS: - read = 0; - - default: - read = 0; - endcase - end - - always @(posedge clk or negedge rst_n) - if(!rst_n) begin - mmu_enable <= 0; - high_vectors <= 0; - dcache_enable <= 0; - icache_enable <= 0; - end else if(transfer && !load) - unique case(op2) - `CP15_SYSCFG_CTRL: begin - mmu_enable <= write_ctrl.m; - high_vectors <= write_ctrl.v; - dcache_enable <= write_ctrl.c; - icache_enable <= write_ctrl.i; - end - - default: ; - endcase - -endmodule diff --git a/rtl/core/cp15/tlb.sv b/rtl/core/cp15/tlb.sv deleted file mode 100644 index 5cbd19d..0000000 --- a/rtl/core/cp15/tlb.sv +++ /dev/null @@ -1,15 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_tlb -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write -); - - //TODO - -endmodule diff --git a/rtl/core/cp15/tlb_lockdown.sv b/rtl/core/cp15/tlb_lockdown.sv deleted file mode 100644 index 1972c33..0000000 --- a/rtl/core/cp15/tlb_lockdown.sv +++ /dev/null @@ -1,18 +0,0 @@ -`include "core/uarch.sv" - -module core_cp15_tlb_lockdown -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - output word read -); - - //TODO, aunque al parecer Linux no usa esto - assign read = 0; - -endmodule diff --git a/rtl/core/cp15/ttbr.sv b/rtl/core/cp15/ttbr.sv deleted file mode 100644 index b462955..0000000 --- a/rtl/core/cp15/ttbr.sv +++ /dev/null @@ -1,45 +0,0 @@ -`include "core/cp15/map.sv" -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_cp15_ttbr -( - input logic clk, - rst_n, - - input logic load, - transfer, - input word write, - - output word read /*verilator public*/, - output mmu_base mmu_ttbr -); - - logic s, c; - cp15_ttbr read_ttbr, write_ttbr; - logic[1:0] rgn; - - assign read = read_ttbr; - assign write_ttbr = write; - - assign read_ttbr.s = s; - assign read_ttbr.c = c; - assign read_ttbr.sbz = 9'd0; - assign read_ttbr.rgn = rgn; - assign read_ttbr.imp = 0; - assign read_ttbr.base = mmu_ttbr; - - always @(posedge clk or negedge rst_n) - if(!rst_n) begin - s <= 0; - c <= 0; - rgn <= 0; - mmu_ttbr <= 0; - end else if(transfer && !load) begin - s <= write_ttbr.s; - c <= write_ttbr.c; - rgn <= write_ttbr.rgn; - mmu_ttbr <= write_ttbr.base; - end - -endmodule diff --git a/rtl/core/cp15_map.sv b/rtl/core/cp15_map.sv new file mode 100644 index 0000000..438a5bf --- /dev/null +++ b/rtl/core/cp15_map.sv @@ -0,0 +1,127 @@ +`ifndef CORE_CP15_MAP_SV +`define CORE_CP15_MAP_SV + +`define CP15_CRN_CPUID 4'd0 +`define CP15_CRN_SYSCFG 4'd1 +`define CP15_CRN_TTBR 4'd2 +`define CP15_CRN_DOMAIN 4'd3 +`define CP15_CRN_FSR 4'd5 +`define CP15_CRN_FAR 4'd6 +`define CP15_CRN_CACHE 4'd7 +`define CP15_CRN_TLB 4'd8 +`define CP15_CRN_CACHE_LCK 4'd9 +`define CP15_CRN_TLB_LCK 4'd10 +`define CP15_CRN_DMA 4'd11 +`define CP15_CRN_PID 4'd13 +`define CP15_CRN_CYCLECNT 4'd15 + +typedef struct packed +{ + logic[31:24] implementor; + logic[23:20] variant; + logic[19:16] architecture; + logic[15:4] part_number; + logic[3:0] revision; +} cp15_cpuid_main; + +`define CP15_CPUID_CACHE 3'b001 + +typedef struct packed +{ + logic[11:11] p; + logic[10:10] mbz; + logic[9:6] size; + logic[5:3] assoc; + logic[2:2] m; + logic[1:0] len; +} cp15_cpuid_cache_size; + +typedef struct packed +{ + logic[31:29] mbz; + logic[28:25] ctype; + logic[24:24] s; + cp15_cpuid_cache_size dsize, + isize; +} cp15_cpuid_cache; + +`define CP15_CPUID_TCM 3'b010 + +typedef struct packed +{ + logic[31:29] mbz; + logic[28:19] sbz0; + logic[18:16] dtcm; + logic[15:3] sbz1; + logic[2:0] itcm; +} cp15_cpuid_tcm; + +`define CP15_CPUID_TLB 3'b011 + +typedef struct packed +{ + logic[31:24] sbz0; + logic[23:16] ilsize; + logic[15:8] dlsize; + logic[7:1] sbz1; + logic[0:0] s; +} cp15_cpuid_tlb; + +`define CP15_CPUID_MPU 3'b100 + +typedef struct packed +{ + logic[31:24] sbz0; + logic[23:16] iregion; + logic[15:8] dregion; + logic[7:1] sbz1; + logic[0:0] s; +} cp15_cpuid_mpu; + +`define CP15_SYSCFG_CTRL 3'b000 + +typedef struct packed +{ + logic[31:27] reserved; + logic[26:26] l2; + logic[25:25] ee; + logic[24:24] ve; + logic[23:23] xp; + logic[22:22] u; + logic[21:21] fi; + logic[20:20] st; + logic[19:19] sbz0; + logic[18:18] it; + logic[17:17] sbz1; + logic[16:16] dt; + logic[15:15] l4; + logic[14:14] rr; + logic[13:13] v; + logic[12:12] i; + logic[11:11] z; + logic[10:10] f; + logic[9:9] r; + logic[8:8] s; + logic[7:7] b; + logic[6:6] l; + logic[5:5] d; + logic[4:4] p; + logic[3:3] w; + logic[2:2] c; + logic[1:1] a; + logic[0:0] m; +} cp15_syscfg_ctrl; + +`define CP15_SYSCFG_ACCESS 3'b010 + +typedef struct packed +{ + logic[31:14] base; + logic[13:5] sbz; + logic[4:3] rgn; + logic[2:2] imp; + logic[1:1] s; + logic[0:0] c; +} cp15_ttbr; + +`endif diff --git a/rtl/core/decode/branch_dec.sv b/rtl/core/decode/branch_dec.sv deleted file mode 100644 index 1dbc1ad..0000000 --- a/rtl/core/decode/branch_dec.sv +++ /dev/null @@ -1,18 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_branch -( - input word insn, - - output logic link, - output ptr offset -); - - logic[23:0] immediate; - assign immediate = insn `FIELD_B_OFFSET; - - assign link = insn `FIELD_B_L; - assign offset = {{6{immediate[23]}}, immediate}; - -endmodule diff --git a/rtl/core/decode/coproc_dec.sv b/rtl/core/decode/coproc_dec.sv deleted file mode 100644 index 153cadf..0000000 --- a/rtl/core/decode/coproc_dec.sv +++ /dev/null @@ -1,24 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_coproc -( - input word insn, - - output coproc_decode decode, - output reg_num rd, - output logic writeback, - update_flags -); - - assign rd = insn `FIELD_CP_RD; - assign writeback = decode.load && rd != `R15; - assign update_flags = decode.load && rd == `R15; - - assign decode.crn = insn `FIELD_CP_CRN; - assign decode.crm = insn `FIELD_CP_CRM; - assign decode.op1 = insn `FIELD_CP_OPCODE; - assign decode.op2 = insn `FIELD_CP_OPCODE2; - assign decode.load = insn `FIELD_CP_LOAD; - -endmodule diff --git a/rtl/core/decode/data_dec.sv b/rtl/core/decode/data_dec.sv deleted file mode 100644 index f744972..0000000 --- a/rtl/core/decode/data_dec.sv +++ /dev/null @@ -1,65 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_data -( - input word insn, - - output data_decode decode, - output logic snd_is_imm, - snd_shift_by_reg_if_reg, - writeback, - conditional, - update_flags, - restore_spsr -); - - alu_op op; - reg_num rn, rd; - logic uses_rn; - - assign decode.op = op; - assign decode.rn = rn; - assign decode.rd = rd; - assign decode.uses_rn = uses_rn; - - assign rn = insn `FIELD_DATA_RN; - assign rd = insn `FIELD_DATA_RD; - assign op = insn `FIELD_DATA_OPCODE; - - assign snd_is_imm = insn `FIELD_DATA_IMM; - assign snd_shift_by_reg_if_reg = insn `FIELD_DATA_REGSHIFT; - - always_comb begin - unique case(op) - `ALU_ADC, `ALU_SBC, `ALU_RSC: - conditional = 1; - - default: - conditional = 0; - endcase - - unique case(op) - `ALU_CMP, `ALU_CMN, `ALU_TST, `ALU_TEQ: - writeback = 0; - - default: - writeback = 1; - endcase - - unique case(op) - `ALU_MOV, `ALU_MVN: - uses_rn = 0; - - default: - uses_rn = 1; - endcase - - update_flags = insn `FIELD_DATA_S; - restore_spsr = (rd == `R15) & update_flags; - - if(restore_spsr) - update_flags = 0; - end - -endmodule diff --git a/rtl/core/decode/decode.sv b/rtl/core/decode/decode.sv deleted file mode 100644 index 219f975..0000000 --- a/rtl/core/decode/decode.sv +++ /dev/null @@ -1,195 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode -( - input word insn, - - output insn_decode dec -); - - mul_decode dec_mul; - psr_decode dec_psr; - snd_decode dec_snd; - ctrl_decode dec_ctrl; - data_decode dec_data; - ldst_decode dec_ldst; - branch_decode dec_branch; - coproc_decode dec_coproc; - - assign dec.mul = dec_mul; - assign dec.psr = dec_psr; - assign dec.snd = dec_snd; - assign dec.ctrl = dec_ctrl; - assign dec.data = dec_data; - assign dec.ldst = dec_ldst; - assign dec.branch = dec_branch; - assign dec.coproc = dec_coproc; - - assign dec_ctrl.nop = 0; - assign dec_ctrl.mul = mul; - assign dec_ctrl.swi = swi; - assign dec_ctrl.psr = psr; - assign dec_ctrl.ldst = ldst; - assign dec_ctrl.bkpt = bkpt; - assign dec_ctrl.branch = branch; - assign dec_ctrl.coproc = coproc; - assign dec_ctrl.execute = execute; - assign dec_ctrl.writeback = writeback; - assign dec_ctrl.undefined = undefined; - assign dec_ctrl.conditional = conditional; - - assign dec_psr.saved = psr_saved; - assign dec_psr.write = psr_write; - assign dec_psr.wr_flags = psr_wr_flags; - assign dec_psr.wr_control = psr_wr_control; - assign dec_psr.update_flags = update_flags; - assign dec_psr.restore_spsr = restore_spsr; - - logic execute, undefined, conditional, writeback, update_flags, - restore_spsr, branch, ldst, mul, swi, psr, coproc, bkpt, - psr_saved, psr_write, psr_wr_flags, psr_wr_control; - - core_decode_mux mux - ( - .* - ); - - logic snd_is_imm, snd_ror_if_imm, snd_shift_by_reg_if_reg, snd_undefined; - snd_decode snd; - - core_decode_snd snd_operand - ( - .decode(snd), - .is_imm(snd_is_imm), - .ror_if_imm(snd_ror_if_imm), - .shift_by_reg_if_reg(snd_shift_by_reg_if_reg), - .undefined(snd_undefined), - .* - ); - - logic branch_link; - - core_decode_branch group_branch - ( - .link(branch_link), - .offset(dec_branch.offset), - .* - ); - - data_decode data; - logic data_writeback, data_update_flags, data_restore_spsr, - data_is_imm, data_shift_by_reg_if_reg, data_conditional; - - core_decode_data group_data - ( - .decode(data), - .writeback(data_writeback), - .conditional(data_conditional), - .update_flags(data_update_flags), - .restore_spsr(data_restore_spsr), - .snd_is_imm(data_is_imm), - .snd_shift_by_reg_if_reg(data_shift_by_reg_if_reg), - .* - ); - - logic ldst_single_is_imm; - ldst_decode ldst_single; - - core_decode_ldst_single group_ldst_single - ( - .snd_is_imm(ldst_single_is_imm), - .decode(ldst_single), - .* - ); - - ldst_decode ldst_misc; - logic ldst_misc_off_is_imm; - reg_num ldst_misc_off_reg; - logic[7:0] ldst_misc_off_imm; - - core_decode_ldst_misc group_ldst_misc - ( - .decode(ldst_misc), - .off_imm(ldst_misc_off_imm), - .off_reg(ldst_misc_off_reg), - .off_is_imm(ldst_misc_off_is_imm), - .* - ); - - logic ldst_mult_restore_spsr; - ldst_decode ldst_multiple; - - core_decode_ldst_multiple group_ldst_multiple - ( - .decode(ldst_multiple), - .restore_spsr(ldst_mult_restore_spsr), - .* - ); - - reg_num ldst_ex_snd_r; - ldst_decode ldst_exclusive; - - core_decode_ldst_exclusive group_ldst_ex - ( - .snd_r(ldst_ex_snd_r), - .decode(ldst_exclusive), - .* - ); - - ldst_decode ldst_addr; - data_decode data_ldst; - - core_decode_ldst_addr ldst2data - ( - .ldst(ldst_addr), - .alu(data_ldst) - ); - - logic mul_update_flags; - reg_num mul_rd, mul_rs, mul_rm; - - core_decode_mul group_mul - ( - .decode(dec_mul), - .rd(mul_rd), - .rs(mul_rs), - .rm(mul_rm), - .update_flags(mul_update_flags), - .* - ); - - logic coproc_writeback, coproc_update_flags; - reg_num coproc_rd; - - core_decode_coproc group_coproc - ( - .rd(coproc_rd), - .decode(dec_coproc), - .writeback(coproc_writeback), - .update_flags(coproc_update_flags), - .* - ); - - logic mrs_spsr; - reg_num mrs_rd; - - core_decode_mrs group_mrs - ( - .rd(mrs_rd), - .spsr(mrs_spsr), - .* - ); - - logic msr_spsr, msr_is_imm; - msr_mask msr_fields; - - core_decode_msr group_msr - ( - .spsr(msr_spsr), - .fields(msr_fields), - .snd_is_imm(msr_is_imm), - .* - ); - -endmodule diff --git a/rtl/core/decode/isa.sv b/rtl/core/decode/isa.sv deleted file mode 100644 index 6784eca..0000000 --- a/rtl/core/decode/isa.sv +++ /dev/null @@ -1,227 +0,0 @@ -`ifndef CORE_DECODE_ISA_SV -`define CORE_DECODE_ISA_SV - -`define FIELD_COND [31:28] -`define FIELD_OP [27:0] - -`define COND_EQ 4'b0000 -`define COND_NE 4'b0001 -`define COND_HS 4'b0010 -`define COND_LO 4'b0011 -`define COND_MI 4'b0100 -`define COND_PL 4'b0101 -`define COND_VS 4'b0110 -`define COND_VC 4'b0111 -`define COND_HI 4'b1000 -`define COND_LS 4'b1001 -`define COND_GE 4'b1010 -`define COND_LT 4'b1011 -`define COND_GT 4'b1100 -`define COND_LE 4'b1101 -`define COND_AL 4'b1110 -`define COND_UD 4'b1111 // Indefnido antes de ARMv5 - -// Necesario para evitar caminos combinacionales largos en ALU -`define FIELD_ALUOP_SUB_SBC [2] -`define FIELD_ALUOP_RSB_RSC [2] -`define FIELD_ALUOP_ADD_CMN [1] -`define FIELD_ALUOP_ADD_NOTCMN_ADC [0] - -// Segundo operando de varios grupos de instrucciones - -`define FIELD_SND_ROR8 [11:8] -`define FIELD_SND_IMM8 [7:0] -`define FIELD_SND_IMM12 [11:0] -`define FIELD_SND_SHIFTIMM [11:7] -`define FIELD_SND_RS [11:8] -`define FIELD_SND_ZEROIFREG [7] -`define FIELD_SND_SHIFT [6:5] -`define FIELD_SND_RM [3:0] - -`define SHIFT_LSL 2'b00 -`define SHIFT_LSR 2'b01 -`define SHIFT_ASR 2'b10 -`define SHIFT_ROR 2'b11 - -// Instrucciones de salto - -`define INSN_B 28'b101_0_???????????????????????? -`define INSN_BL 28'b101_1_???????????????????????? - -// Esto no es parte de ARMv4, pero U-boot tiene algunos `bx lr` hard-coded -`define INSN_BXLR 28'h12fff1e - -`define GROUP_B 28'b101_?_???????????????????????? - -`define FIELD_B_L [24] -`define FIELD_B_OFFSET [23:0] - -// Instrucciones de procesamiento de datos (aritmético-lógicas y MOV) - -`define INSN_AND 28'b00_?_0000_?_????_????_???????????? -`define INSN_EOR 28'b00_?_0001_?_????_????_???????????? -`define INSN_SUB 28'b00_?_0010_?_????_????_???????????? -`define INSN_RSB 28'b00_?_0011_?_????_????_???????????? -`define INSN_ADD 28'b00_?_0100_?_????_????_???????????? -`define INSN_ADC 28'b00_?_0101_?_????_????_???????????? -`define INSN_SBC 28'b00_?_0110_?_????_????_???????????? -`define INSN_RSC 28'b00_?_0111_?_????_????_???????????? -`define INSN_TST 28'b00_?_1000_1_????_0000_???????????? -`define INSN_TEQ 28'b00_?_1001_1_????_0000_???????????? -`define INSN_CMP 28'b00_?_1010_1_????_0000_???????????? -`define INSN_CMN 28'b00_?_1011_1_????_0000_???????????? -`define INSN_ORR 28'b00_?_1100_?_????_????_???????????? -`define INSN_MOV 28'b00_?_1101_?_0000_????_???????????? -`define INSN_BIC 28'b00_?_1110_?_????_????_???????????? -`define INSN_MVN 28'b00_?_1111_?_0000_????_???????????? - -`define GROUP_ALU \ - `INSN_AND, `INSN_EOR, `INSN_SUB, `INSN_RSB, `INSN_ADD, `INSN_ADC, `INSN_SBC, `INSN_RSC, \ - `INSN_TST, `INSN_TEQ, `INSN_CMP, `INSN_CMN, `INSN_ORR, `INSN_MOV, `INSN_BIC, `INSN_MVN - -`define FIELD_DATA_IMM [25] -`define FIELD_DATA_OPCODE [24:21] -`define FIELD_DATA_S [20] -`define FIELD_DATA_RN [19:16] -`define FIELD_DATA_RD [15:12] -`define FIELD_DATA_REGSHIFT [4] - -// Instrucciones de multiplicación - -`define INSN_MUL 28'b0000000_?_????_0000_????_1001_???? -`define INSN_MLA 28'b0000001_?_????_????_????_1001_???? -`define INSN_UMULL 28'b0000100_?_????_????_????_1001_???? -`define INSN_UMLAL 28'b0000101_?_????_????_????_1001_???? -`define INSN_SMULL 28'b0000110_?_????_????_????_1001_???? -`define INSN_SMLAL 28'b0000111_?_????_????_????_1001_???? - -`define GROUP_MUL `INSN_MUL, `INSN_MLA, `INSN_UMULL, `INSN_UMLAL, `INSN_SMULL, `INSN_SMLAL - -`define FIELD_MUL_LONG [23] -`define FIELD_MUL_SIGNED [22] -`define FIELD_MUL_ACC [21] -`define FIELD_MUL_S [20] -`define FIELD_MUL_RD [19:16] -`define FIELD_MUL_RN [15:12] -`define FIELD_MUL_RS [11:8] -`define FIELD_MUL_RM [3:0] - -// Instrucciones de load/store - -`define INSN_LDR 28'b01_?_?_?_0_?_1_????_????_???????????? -`define INSN_LDRB 28'b01_?_?_?_1_?_1_????_????_???????????? -`define INSN_LDRBT 28'b01_?_0_?_1_1_1_????_????_???????????? -`define INSN_LDRT 28'b01_?_0_?_0_1_1_????_????_???????????? -`define INSN_STR 28'b01_?_?_?_0_?_0_????_????_???????????? -`define INSN_STRB 28'b01_?_?_?_1_?_0_????_????_???????????? -`define INSN_STRBT 28'b01_?_0_?_1_1_0_????_????_???????????? -`define INSN_STRT 28'b01_?_0_?_0_1_0_????_????_???????????? - -`define INSN_LDRH 28'b000_?_?_?_?_1_????_????_????_1011_???? -`define INSN_LDRSB 28'b000_?_?_?_?_1_????_????_????_1101_???? -`define INSN_LDRSH 28'b000_?_?_?_?_1_????_????_????_1111_???? -`define INSN_STRH 28'b000_?_?_?_?_0_????_????_????_1011_???? - -`define INSN_LDM_CUR 28'b100_?_?_0_?_1_????_???????????????? -`define INSN_LDM_USR 28'b100_?_?_1_0_1_????_0_??????????????? -`define INSN_LDM_RFE 28'b100_?_?_1_?_1_????_1_??????????????? -`define INSN_STM_CUR 28'b100_?_?_0_?_0_????_???????????????? -`define INSN_STM_USR 28'b100_?_?_1_0_0_????_???????????????? - -`define GROUP_LDST_SINGLE_IMM 28'b01_0_?_?_?_?_?_????_????_???????????? -`define GROUP_LDST_SINGLE_REG 28'b01_1_?_?_?_?_?_????_????_?????_??_0_???? -`define GROUP_LDST_SINGLE `GROUP_LDST_SINGLE_IMM, `GROUP_LDST_SINGLE_REG -`define GROUP_LDST_MISC `INSN_LDRH, `INSN_LDRSB, `INSN_LDRSH, `INSN_STRH -`define GROUP_LDST_MULT 28'b100_?_?_?_?_?_????_???????????????? - -`define FIELD_LDST_LD [20] -`define FIELD_LDST_SINGLE_REG [25] -`define FIELD_LDST_SINGLE_P [24] -`define FIELD_LDST_SINGLE_U [23] -`define FIELD_LDST_SINGLE_B [22] -`define FIELD_LDST_SINGLE_W [21] -`define FIELD_LDST_SINGLE_RN [19:16] -`define FIELD_LDST_SINGLE_RD [15:12] - -`define FIELD_LDST_MISC_P [24] -`define FIELD_LDST_MISC_U [23] -`define FIELD_LDST_MISC_IMM [22] -`define FIELD_LDST_MISC_W [21] -`define FIELD_LDST_MISC_RN [19:16] -`define FIELD_LDST_MISC_RD [15:12] -`define FIELD_LDST_MISC_IMM_HI [11:8] -`define FIELD_LDST_MISC_S [6] -`define FIELD_LDST_MISC_H [5] -`define FIELD_LDST_MISC_IMM_LO [3:0] -`define FIELD_LDST_MISC_RM [3:0] - -`define FIELD_LDST_MULT_P [24] -`define FIELD_LDST_MULT_U [23] -`define FIELD_LDST_MULT_S [22] -`define FIELD_LDST_MULT_W [21] -`define FIELD_LDST_MULT_RN [19:16] -`define FIELD_LDST_MULT_LIST [15:0] - -// Instrucciones para operaciones atómicas optimistas (monitor exclusivo) - -`define INSN_LDREX 28'b0001100_1_????_????_1111_1001_1111 -`define INSN_STREX 28'b0001100_0_????_????_1111_1001_???? -`define GROUP_LDST_EX `INSN_LDREX, `INSN_STREX - -`define FIELD_LDST_EX_LD [20] -`define FIELD_LDST_EX_RN [19:16] -`define FIELD_LDST_EX_RD [15:12] -`define FIELD_LDST_EX_R_OK [3:0] - -// Instrucciones atómicas de intercambio registro-memoria (deprecadas) - -`define INSN_SWP 28'b00010000_????_????_0000_1001_???? -`define INSN_SWPB 28'b00010100_????_????_0000_1001_???? - -`define GROUP_SWP 28'b00010?00_????_????_0000_1001_???? - -`define FIELD_SWP_BYTE [22] -`define FIELD_SWP_RN [19:16] -`define FIELD_SWP_RD [15:12] -`define FIELD_SWP_RM [3:0] - -// Instrucciones de coprocesador, solo definido para CP15 - -`define INSN_MCR 28'b1110_???_0_????_????_1111_???_1_???? -`define INSN_MRC 28'b1110_???_1_????_????_1111_???_1_???? - -`define GROUP_CP 28'b1110_???_?_????_????_1111_???_1_???? - -`define FIELD_CP_OPCODE [23:21] -`define FIELD_CP_LOAD [20] -`define FIELD_CP_CRN [19:16] -`define FIELD_CP_RD [15:12] -`define FIELD_CP_NUM [11:8] -`define FIELD_CP_OPCODE2 [7:5] -`define FIELD_CP_CRM [3:0] - -// Instrucciones de CPSR/SPSR - -`define INSN_MRS 28'b0_0_0_1_0_?_0_0_1111_????_000000000000 -`define INSN_MSR_IMM 28'b0_0_1_1_0_?_1_0_????_1111_????_???????? -`define INSN_MSR_REG 28'b0_0_0_1_0_?_1_0_????_1111_0000_0000_???? - -`define GROUP_MSR `INSN_MSR_IMM, `INSN_MSR_REG - -`define FIELD_MRS_R [22] -`define FIELD_MRS_RD [15:12] -`define FIELD_MSR_I [25] -`define FIELD_MSR_R [22] -`define FIELD_MSR_MASK [19:16] - -// System call - -`define INSN_SWI 28'b1111_???????????????????????? - -`define FIELD_SWI_IMM [23:0] - -// GDB swbreak (a magic 'und') - -`define INSN_GDB_SWBREAK 28'h7ffdefe - -`endif diff --git a/rtl/core/decode/ldst/addr.sv b/rtl/core/decode/ldst/addr.sv deleted file mode 100644 index 345f0ea..0000000 --- a/rtl/core/decode/ldst/addr.sv +++ /dev/null @@ -1,15 +0,0 @@ -`include "core/uarch.sv" - -module core_decode_ldst_addr -( - input ldst_decode ldst, - - output data_decode alu -); - - assign alu.op = ldst.increment ? `ALU_ADD : `ALU_SUB; - assign alu.rn = ldst.rn; - assign alu.rd = ldst.rd; - assign alu.uses_rn = 1; - -endmodule diff --git a/rtl/core/decode/ldst/exclusive.sv b/rtl/core/decode/ldst/exclusive.sv deleted file mode 100644 index 7942a04..0000000 --- a/rtl/core/decode/ldst/exclusive.sv +++ /dev/null @@ -1,27 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_ldst_exclusive -( - input word insn, - - output ldst_decode decode, - output reg_num snd_r -); - - assign snd_r = insn `FIELD_LDST_EX_R_OK; - - assign decode.rn = insn `FIELD_LDST_EX_RN; - assign decode.rd = insn `FIELD_LDST_EX_RD; - assign decode.size = LDST_WORD; - assign decode.load = insn `FIELD_LDST_EX_LD; - assign decode.increment = 0; - assign decode.writeback = 0; - assign decode.exclusive = 1; - assign decode.sign_extend = 0; - assign decode.pre_indexed = 0; - assign decode.unprivileged = 0; - assign decode.user_regs = 0; - assign decode.regs = 16'b0; - -endmodule diff --git a/rtl/core/decode/ldst/misc.sv b/rtl/core/decode/ldst/misc.sv deleted file mode 100644 index 72d648c..0000000 --- a/rtl/core/decode/ldst/misc.sv +++ /dev/null @@ -1,36 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_ldst_misc -( - input word insn, - - output ldst_decode decode, - output logic off_is_imm, - output logic[7:0] off_imm, - output reg_num off_reg -); - - logic p, w; - - assign decode.rn = insn `FIELD_LDST_MISC_RN; - assign decode.rd = insn `FIELD_LDST_MISC_RD; - assign decode.size = insn `FIELD_LDST_MISC_H ? LDST_HALF : LDST_BYTE; - assign decode.load = insn `FIELD_LDST_LD; - assign decode.increment = insn `FIELD_LDST_MISC_U; - assign decode.writeback = !p || w; - assign decode.exclusive = 0; - assign decode.sign_extend = insn `FIELD_LDST_MISC_S; - assign decode.pre_indexed = p; - assign decode.unprivileged = 0; - assign decode.user_regs = 0; - assign decode.regs = 16'b0; - - assign off_imm = {insn `FIELD_LDST_MISC_IMM_HI, insn `FIELD_LDST_MISC_IMM_LO}; - assign off_reg = insn `FIELD_LDST_MISC_RM; - assign off_is_imm = insn `FIELD_LDST_MISC_IMM; - - assign p = insn `FIELD_LDST_MISC_P; - assign w = insn `FIELD_LDST_MISC_W; - -endmodule diff --git a/rtl/core/decode/ldst/multiple.sv b/rtl/core/decode/ldst/multiple.sv deleted file mode 100644 index c822ab0..0000000 --- a/rtl/core/decode/ldst/multiple.sv +++ /dev/null @@ -1,34 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_ldst_multiple -( - input word insn, - - output ldst_decode decode, - output logic restore_spsr -); - - logic s, l; - reg_list regs; - - assign decode.rn = insn `FIELD_LDST_MULT_RN; - assign decode.rd = 4'bxxxx; - assign decode.size = LDST_WORD; - assign decode.load = l; - assign decode.increment = insn `FIELD_LDST_MULT_U; - assign decode.writeback = insn `FIELD_LDST_MULT_W; - assign decode.exclusive = 0; - assign decode.sign_extend = 0; - assign decode.pre_indexed = insn `FIELD_LDST_MULT_P; - assign decode.unprivileged = 0; - assign decode.user_regs = s && !(l && regs[`R15]); - assign decode.regs = regs; - - assign s = insn `FIELD_LDST_MULT_S; - assign l = insn `FIELD_LDST_LD; - - assign regs = insn `FIELD_LDST_MULT_LIST; - assign restore_spsr = s && l && regs[`R15]; - -endmodule diff --git a/rtl/core/decode/ldst/single.sv b/rtl/core/decode/ldst/single.sv deleted file mode 100644 index af096a7..0000000 --- a/rtl/core/decode/ldst/single.sv +++ /dev/null @@ -1,31 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_ldst_single -( - input word insn, - - output ldst_decode decode, - output logic snd_is_imm -); - - logic p, w; - - assign decode.rn = insn `FIELD_LDST_SINGLE_RN; - assign decode.rd = insn `FIELD_LDST_SINGLE_RD; - assign decode.size = insn `FIELD_LDST_SINGLE_B ? LDST_BYTE : LDST_WORD; - assign decode.load = insn `FIELD_LDST_LD; - assign decode.increment = insn `FIELD_LDST_SINGLE_U; - assign decode.writeback = !p || w; - assign decode.exclusive = 0; - assign decode.sign_extend = 0; - assign decode.pre_indexed = p; - assign decode.unprivileged = !p && w; - assign decode.user_regs = 0; - assign decode.regs = 16'b0; - - assign p = insn `FIELD_LDST_SINGLE_P; - assign w = insn `FIELD_LDST_SINGLE_W; - assign snd_is_imm = !insn `FIELD_LDST_SINGLE_REG; - -endmodule diff --git a/rtl/core/decode/mrs.sv b/rtl/core/decode/mrs.sv deleted file mode 100644 index 05018cd..0000000 --- a/rtl/core/decode/mrs.sv +++ /dev/null @@ -1,15 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_mrs -( - input word insn, - - output reg_num rd, - output logic spsr -); - - assign rd = insn `FIELD_MRS_RD; - assign spsr = insn `FIELD_MRS_R; - -endmodule diff --git a/rtl/core/decode/msr.sv b/rtl/core/decode/msr.sv deleted file mode 100644 index c3f0e3d..0000000 --- a/rtl/core/decode/msr.sv +++ /dev/null @@ -1,17 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_msr -( - input word insn, - - output msr_mask fields, - output logic spsr, - snd_is_imm -); - - assign spsr = insn `FIELD_MSR_R; - assign fields = insn `FIELD_MSR_MASK; - assign snd_is_imm = insn `FIELD_MSR_I; - -endmodule diff --git a/rtl/core/decode/mul_dec.sv b/rtl/core/decode/mul_dec.sv deleted file mode 100644 index 114b65b..0000000 --- a/rtl/core/decode/mul_dec.sv +++ /dev/null @@ -1,33 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_mul -( - input word insn, - - output mul_decode decode, - output reg_num rd, - rs, - rm, - output logic update_flags -); - - logic long_mul; - reg_num short_rd, rn; - - assign rd = long_mul ? rn : short_rd; - assign rs = insn `FIELD_MUL_RS; - assign rm = insn `FIELD_MUL_RM; - assign update_flags = insn `FIELD_MUL_S; - - assign decode.add = insn `FIELD_MUL_ACC; - assign decode.long_mul = long_mul; - assign decode.signed_mul = insn `FIELD_MUL_SIGNED; - assign decode.r_add_lo = rn; - assign decode.r_add_hi = short_rd; - - assign long_mul = insn `FIELD_MUL_LONG; - assign short_rd = insn `FIELD_MUL_RD; - assign rn = insn `FIELD_MUL_RN; - -endmodule diff --git a/rtl/core/decode/mux.sv b/rtl/core/decode/mux.sv deleted file mode 100644 index 6f0451a..0000000 --- a/rtl/core/decode/mux.sv +++ /dev/null @@ -1,295 +0,0 @@ -`include "core/decode/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: - //`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 diff --git a/rtl/core/decode/snd.sv b/rtl/core/decode/snd.sv deleted file mode 100644 index 264982e..0000000 --- a/rtl/core/decode/snd.sv +++ /dev/null @@ -1,75 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_decode_snd -( - input word insn, - input logic is_imm, - ror_if_imm, - shift_by_reg_if_reg, - - output snd_decode decode, - output logic undefined -); - - reg_num r, r_shift; - logic shift_by_reg, shr, ror, put_carry, sign_extend; - logic[11:0] imm; - logic[5:0] shift_imm; - - assign decode.r = r; - assign decode.r_shift = r_shift; - assign decode.shift_by_reg = shift_by_reg; - assign decode.is_imm = is_imm; - assign decode.shr = shr; - assign decode.ror = ror; - assign decode.put_carry = put_carry; - assign decode.sign_extend = sign_extend; - assign decode.imm = imm; - assign decode.shift_imm = shift_imm; - - assign r = insn `FIELD_SND_RM; - assign r_shift = insn `FIELD_SND_RS; - assign imm = ror_if_imm ? {4'b0, insn `FIELD_SND_IMM8} : insn `FIELD_SND_IMM12; - assign shift_by_reg = ~is_imm & shift_by_reg_if_reg; - assign undefined = shift_by_reg & insn `FIELD_SND_ZEROIFREG; - - logic[1:0] shift_op; - assign shift_op = insn `FIELD_SND_SHIFT; - - always_comb begin - ror = is_imm; - shr = ~is_imm; - put_carry = 0; - sign_extend = 0; - - if(is_imm) - shift_imm = ror_if_imm ? {1'b0, insn `FIELD_SND_ROR8, 1'b0} : 6'b0; - else begin - shift_imm = {1'b0, insn `FIELD_SND_SHIFTIMM}; - - case(shift_op) - `SHIFT_LSL: shr = 0; - `SHIFT_LSR: ; - `SHIFT_ASR: sign_extend = 1; - `SHIFT_ROR: ror = 1; - endcase - - if(!shift_by_reg && shift_imm == 0) - case(shift_op) - `SHIFT_LSL: ; - - `SHIFT_LSR, `SHIFT_ASR: - shift_imm = 6'd32; - - `SHIFT_ROR: begin - // RRX - ror = 0; - shift_imm = 6'd1; - put_carry = 1; - end - endcase - end - end - -endmodule diff --git a/rtl/core/fetch/fetch.sv b/rtl/core/fetch/fetch.sv deleted file mode 100644 index 279d2c2..0000000 --- a/rtl/core/fetch/fetch.sv +++ /dev/null @@ -1,74 +0,0 @@ -`include "core/uarch.sv" - -module core_fetch -#(parameter PREFETCH_ORDER=2) -( - input logic clk, - rst_n, - stall, - fault, - fetched, - explicit_branch /*verilator public*/ /*verilator forceable*/, - wr_pc, - prefetch_flush, - input ptr branch_target, - porch_insn_pc, - input word wr_current, - fetch_data, - - output logic fetch, - flush, - nop, - output word insn, - output ptr insn_pc, - addr, - fetch_head, - output logic insn_abort -); - - ptr target /*verilator public*/ /*verilator forceable*/, hold_addr; - logic branch, prefetch_ready, fetched_valid, discard, pending, next_pending; - - assign fetch = prefetch_ready && !discard; - assign flush = branch || prefetch_flush; - assign branch = explicit_branch || wr_pc; - assign target = wr_pc ? wr_current[31:2] : branch_target; //TODO: alignment exception - assign next_pending = fetch || (pending && !fetched); - assign fetched_valid = fetched && !discard; - - core_prefetch #(.ORDER(PREFETCH_ORDER)) prefetch - ( - .head(fetch_head), - .fetched(fetched_valid), - .fetch(prefetch_ready), - .* - ); - - always_comb begin - if(branch) - fetch_head = target; - else if(prefetch_flush) - fetch_head = porch_insn_pc; - else - fetch_head = {30{1'bx}}; - - if(flush) - addr = fetch_head; - else if(fetch && fetched_valid) - addr = hold_addr + 1; - else - addr = hold_addr; - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - pending <= 0; - discard <= 0; - hold_addr <= 0; - end else begin - pending <= next_pending; - discard <= next_pending && (discard || flush); - hold_addr <= addr; - end - -endmodule diff --git a/rtl/core/fetch/prefetch.sv b/rtl/core/fetch/prefetch.sv deleted file mode 100644 index 719ad95..0000000 --- a/rtl/core/fetch/prefetch.sv +++ /dev/null @@ -1,84 +0,0 @@ -`include "core/uarch.sv" - -module core_prefetch -#(parameter ORDER=2) -( - input logic clk, - rst_n, - stall, - flush, - fault, - fetched, - input word fetch_data, - input ptr head, - - output word insn, - output ptr insn_pc, - output logic fetch, - nop, - insn_abort -); - - localparam SIZE = (1 << ORDER) - 1; - - ptr next_pc; - logic faults[SIZE]; - logic[31:0] prefetch[SIZE]; - logic[ORDER - 1:0] valid; - - assign nop = flush ? 1 : ~|valid; - assign insn = flush ? `NOP : prefetch[0]; - assign fetch = !stall || ~&valid; - assign next_pc = ~stall & |valid ? insn_pc + 1 : insn_pc; - assign insn_abort = flush ? 0 : faults[0]; - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - valid <= 0; - insn_pc <= 0; - - faults[SIZE - 1] <= 0; - prefetch[SIZE - 1] <= `NOP; - end else begin - insn_pc <= flush ? head : next_pc; - - if(flush) begin - faults[SIZE - 1] <= 0; - prefetch[SIZE - 1] <= `NOP; - end else if(fetched && valid == SIZE - 1 + {{(ORDER - 1){1'b0}}, !stall}) begin - faults[SIZE - 1] <= fault; - prefetch[SIZE - 1] <= fetch_data; - end else if(!stall) begin - faults[SIZE - 1] <= 0; - prefetch[SIZE - 1] <= `NOP; - end - - if(flush) - valid <= 0; - else if(fetched & ((stall & ~&valid) | ~|valid)) - valid <= valid + 1; - else if(~stall & ~fetched & |valid) - valid <= valid - 1; - end - - genvar i; - generate - for(i = 0; i < SIZE - 1; ++i) begin: prefetch_slots - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - faults[i] <= 0; - prefetch[i] <= `NOP; - end else if(flush) begin - faults[i] <= 0; - prefetch[i] <= `NOP; - end else if(fetched & (~(|i | |valid) | (valid == i + {{(ORDER - 1){1'b0}}, ~stall}))) begin - faults[i] <= fault; - prefetch[i] <= fetch_data; - end else if(~stall) begin - faults[i] <= faults[i + 1]; - prefetch[i] <= prefetch[i + 1]; - end - end - endgenerate - -endmodule diff --git a/rtl/core/isa.sv b/rtl/core/isa.sv new file mode 100644 index 0000000..6784eca --- /dev/null +++ b/rtl/core/isa.sv @@ -0,0 +1,227 @@ +`ifndef CORE_DECODE_ISA_SV +`define CORE_DECODE_ISA_SV + +`define FIELD_COND [31:28] +`define FIELD_OP [27:0] + +`define COND_EQ 4'b0000 +`define COND_NE 4'b0001 +`define COND_HS 4'b0010 +`define COND_LO 4'b0011 +`define COND_MI 4'b0100 +`define COND_PL 4'b0101 +`define COND_VS 4'b0110 +`define COND_VC 4'b0111 +`define COND_HI 4'b1000 +`define COND_LS 4'b1001 +`define COND_GE 4'b1010 +`define COND_LT 4'b1011 +`define COND_GT 4'b1100 +`define COND_LE 4'b1101 +`define COND_AL 4'b1110 +`define COND_UD 4'b1111 // Indefnido antes de ARMv5 + +// Necesario para evitar caminos combinacionales largos en ALU +`define FIELD_ALUOP_SUB_SBC [2] +`define FIELD_ALUOP_RSB_RSC [2] +`define FIELD_ALUOP_ADD_CMN [1] +`define FIELD_ALUOP_ADD_NOTCMN_ADC [0] + +// Segundo operando de varios grupos de instrucciones + +`define FIELD_SND_ROR8 [11:8] +`define FIELD_SND_IMM8 [7:0] +`define FIELD_SND_IMM12 [11:0] +`define FIELD_SND_SHIFTIMM [11:7] +`define FIELD_SND_RS [11:8] +`define FIELD_SND_ZEROIFREG [7] +`define FIELD_SND_SHIFT [6:5] +`define FIELD_SND_RM [3:0] + +`define SHIFT_LSL 2'b00 +`define SHIFT_LSR 2'b01 +`define SHIFT_ASR 2'b10 +`define SHIFT_ROR 2'b11 + +// Instrucciones de salto + +`define INSN_B 28'b101_0_???????????????????????? +`define INSN_BL 28'b101_1_???????????????????????? + +// Esto no es parte de ARMv4, pero U-boot tiene algunos `bx lr` hard-coded +`define INSN_BXLR 28'h12fff1e + +`define GROUP_B 28'b101_?_???????????????????????? + +`define FIELD_B_L [24] +`define FIELD_B_OFFSET [23:0] + +// Instrucciones de procesamiento de datos (aritmético-lógicas y MOV) + +`define INSN_AND 28'b00_?_0000_?_????_????_???????????? +`define INSN_EOR 28'b00_?_0001_?_????_????_???????????? +`define INSN_SUB 28'b00_?_0010_?_????_????_???????????? +`define INSN_RSB 28'b00_?_0011_?_????_????_???????????? +`define INSN_ADD 28'b00_?_0100_?_????_????_???????????? +`define INSN_ADC 28'b00_?_0101_?_????_????_???????????? +`define INSN_SBC 28'b00_?_0110_?_????_????_???????????? +`define INSN_RSC 28'b00_?_0111_?_????_????_???????????? +`define INSN_TST 28'b00_?_1000_1_????_0000_???????????? +`define INSN_TEQ 28'b00_?_1001_1_????_0000_???????????? +`define INSN_CMP 28'b00_?_1010_1_????_0000_???????????? +`define INSN_CMN 28'b00_?_1011_1_????_0000_???????????? +`define INSN_ORR 28'b00_?_1100_?_????_????_???????????? +`define INSN_MOV 28'b00_?_1101_?_0000_????_???????????? +`define INSN_BIC 28'b00_?_1110_?_????_????_???????????? +`define INSN_MVN 28'b00_?_1111_?_0000_????_???????????? + +`define GROUP_ALU \ + `INSN_AND, `INSN_EOR, `INSN_SUB, `INSN_RSB, `INSN_ADD, `INSN_ADC, `INSN_SBC, `INSN_RSC, \ + `INSN_TST, `INSN_TEQ, `INSN_CMP, `INSN_CMN, `INSN_ORR, `INSN_MOV, `INSN_BIC, `INSN_MVN + +`define FIELD_DATA_IMM [25] +`define FIELD_DATA_OPCODE [24:21] +`define FIELD_DATA_S [20] +`define FIELD_DATA_RN [19:16] +`define FIELD_DATA_RD [15:12] +`define FIELD_DATA_REGSHIFT [4] + +// Instrucciones de multiplicación + +`define INSN_MUL 28'b0000000_?_????_0000_????_1001_???? +`define INSN_MLA 28'b0000001_?_????_????_????_1001_???? +`define INSN_UMULL 28'b0000100_?_????_????_????_1001_???? +`define INSN_UMLAL 28'b0000101_?_????_????_????_1001_???? +`define INSN_SMULL 28'b0000110_?_????_????_????_1001_???? +`define INSN_SMLAL 28'b0000111_?_????_????_????_1001_???? + +`define GROUP_MUL `INSN_MUL, `INSN_MLA, `INSN_UMULL, `INSN_UMLAL, `INSN_SMULL, `INSN_SMLAL + +`define FIELD_MUL_LONG [23] +`define FIELD_MUL_SIGNED [22] +`define FIELD_MUL_ACC [21] +`define FIELD_MUL_S [20] +`define FIELD_MUL_RD [19:16] +`define FIELD_MUL_RN [15:12] +`define FIELD_MUL_RS [11:8] +`define FIELD_MUL_RM [3:0] + +// Instrucciones de load/store + +`define INSN_LDR 28'b01_?_?_?_0_?_1_????_????_???????????? +`define INSN_LDRB 28'b01_?_?_?_1_?_1_????_????_???????????? +`define INSN_LDRBT 28'b01_?_0_?_1_1_1_????_????_???????????? +`define INSN_LDRT 28'b01_?_0_?_0_1_1_????_????_???????????? +`define INSN_STR 28'b01_?_?_?_0_?_0_????_????_???????????? +`define INSN_STRB 28'b01_?_?_?_1_?_0_????_????_???????????? +`define INSN_STRBT 28'b01_?_0_?_1_1_0_????_????_???????????? +`define INSN_STRT 28'b01_?_0_?_0_1_0_????_????_???????????? + +`define INSN_LDRH 28'b000_?_?_?_?_1_????_????_????_1011_???? +`define INSN_LDRSB 28'b000_?_?_?_?_1_????_????_????_1101_???? +`define INSN_LDRSH 28'b000_?_?_?_?_1_????_????_????_1111_???? +`define INSN_STRH 28'b000_?_?_?_?_0_????_????_????_1011_???? + +`define INSN_LDM_CUR 28'b100_?_?_0_?_1_????_???????????????? +`define INSN_LDM_USR 28'b100_?_?_1_0_1_????_0_??????????????? +`define INSN_LDM_RFE 28'b100_?_?_1_?_1_????_1_??????????????? +`define INSN_STM_CUR 28'b100_?_?_0_?_0_????_???????????????? +`define INSN_STM_USR 28'b100_?_?_1_0_0_????_???????????????? + +`define GROUP_LDST_SINGLE_IMM 28'b01_0_?_?_?_?_?_????_????_???????????? +`define GROUP_LDST_SINGLE_REG 28'b01_1_?_?_?_?_?_????_????_?????_??_0_???? +`define GROUP_LDST_SINGLE `GROUP_LDST_SINGLE_IMM, `GROUP_LDST_SINGLE_REG +`define GROUP_LDST_MISC `INSN_LDRH, `INSN_LDRSB, `INSN_LDRSH, `INSN_STRH +`define GROUP_LDST_MULT 28'b100_?_?_?_?_?_????_???????????????? + +`define FIELD_LDST_LD [20] +`define FIELD_LDST_SINGLE_REG [25] +`define FIELD_LDST_SINGLE_P [24] +`define FIELD_LDST_SINGLE_U [23] +`define FIELD_LDST_SINGLE_B [22] +`define FIELD_LDST_SINGLE_W [21] +`define FIELD_LDST_SINGLE_RN [19:16] +`define FIELD_LDST_SINGLE_RD [15:12] + +`define FIELD_LDST_MISC_P [24] +`define FIELD_LDST_MISC_U [23] +`define FIELD_LDST_MISC_IMM [22] +`define FIELD_LDST_MISC_W [21] +`define FIELD_LDST_MISC_RN [19:16] +`define FIELD_LDST_MISC_RD [15:12] +`define FIELD_LDST_MISC_IMM_HI [11:8] +`define FIELD_LDST_MISC_S [6] +`define FIELD_LDST_MISC_H [5] +`define FIELD_LDST_MISC_IMM_LO [3:0] +`define FIELD_LDST_MISC_RM [3:0] + +`define FIELD_LDST_MULT_P [24] +`define FIELD_LDST_MULT_U [23] +`define FIELD_LDST_MULT_S [22] +`define FIELD_LDST_MULT_W [21] +`define FIELD_LDST_MULT_RN [19:16] +`define FIELD_LDST_MULT_LIST [15:0] + +// Instrucciones para operaciones atómicas optimistas (monitor exclusivo) + +`define INSN_LDREX 28'b0001100_1_????_????_1111_1001_1111 +`define INSN_STREX 28'b0001100_0_????_????_1111_1001_???? +`define GROUP_LDST_EX `INSN_LDREX, `INSN_STREX + +`define FIELD_LDST_EX_LD [20] +`define FIELD_LDST_EX_RN [19:16] +`define FIELD_LDST_EX_RD [15:12] +`define FIELD_LDST_EX_R_OK [3:0] + +// Instrucciones atómicas de intercambio registro-memoria (deprecadas) + +`define INSN_SWP 28'b00010000_????_????_0000_1001_???? +`define INSN_SWPB 28'b00010100_????_????_0000_1001_???? + +`define GROUP_SWP 28'b00010?00_????_????_0000_1001_???? + +`define FIELD_SWP_BYTE [22] +`define FIELD_SWP_RN [19:16] +`define FIELD_SWP_RD [15:12] +`define FIELD_SWP_RM [3:0] + +// Instrucciones de coprocesador, solo definido para CP15 + +`define INSN_MCR 28'b1110_???_0_????_????_1111_???_1_???? +`define INSN_MRC 28'b1110_???_1_????_????_1111_???_1_???? + +`define GROUP_CP 28'b1110_???_?_????_????_1111_???_1_???? + +`define FIELD_CP_OPCODE [23:21] +`define FIELD_CP_LOAD [20] +`define FIELD_CP_CRN [19:16] +`define FIELD_CP_RD [15:12] +`define FIELD_CP_NUM [11:8] +`define FIELD_CP_OPCODE2 [7:5] +`define FIELD_CP_CRM [3:0] + +// Instrucciones de CPSR/SPSR + +`define INSN_MRS 28'b0_0_0_1_0_?_0_0_1111_????_000000000000 +`define INSN_MSR_IMM 28'b0_0_1_1_0_?_1_0_????_1111_????_???????? +`define INSN_MSR_REG 28'b0_0_0_1_0_?_1_0_????_1111_0000_0000_???? + +`define GROUP_MSR `INSN_MSR_IMM, `INSN_MSR_REG + +`define FIELD_MRS_R [22] +`define FIELD_MRS_RD [15:12] +`define FIELD_MSR_I [25] +`define FIELD_MSR_R [22] +`define FIELD_MSR_MASK [19:16] + +// System call + +`define INSN_SWI 28'b1111_???????????????????????? + +`define FIELD_SWI_IMM [23:0] + +// GDB swbreak (a magic 'und') + +`define INSN_GDB_SWBREAK 28'h7ffdefe + +`endif diff --git a/rtl/core/mmu/arbiter.sv b/rtl/core/mmu/arbiter.sv deleted file mode 100644 index b0da7c8..0000000 --- a/rtl/core/mmu/arbiter.sv +++ /dev/null @@ -1,132 +0,0 @@ -module core_mmu_arbiter -( - input logic clk, - rst_n, - - input logic bus_ready, - bus_ex_fail, - input word bus_data_rd, - data_data_wr, - input ptr insn_addr, - data_addr, - input logic insn_start, - data_start, - data_write, - data_ex_lock, - input logic[3:0] data_data_be, - - output word bus_data_wr, - output logic[3:0] bus_data_be, - output ptr bus_addr, - output logic bus_start, - bus_write, - bus_ex_lock, - insn_ready, - data_ready, - data_ex_fail, - output word insn_data_rd, - data_data_rd -); - - enum int unsigned - { - INSN, - DATA - } master, next_master; - - ptr hold_addr; - word hold_data_wr; - logic active, hold_ex_lock, hold_start, hold_write, hold_issue, hold_free, transition; - logic[3:0] hold_data_be; - - assign data_ex_fail = bus_ex_fail; - assign insn_data_rd = bus_data_rd; - assign data_data_rd = bus_data_rd; - - always_comb begin - next_master = master; - if(bus_ready || !active) - unique case(master) - DATA: next_master = data_start ? DATA : INSN; - INSN: next_master = !data_start && !hold_start ? INSN : DATA; - endcase - - // Causa UNOPTFLAT en Verilator con assign - transition = master != next_master; - hold_issue = transition && hold_start; - hold_free = transition || !hold_start; - - insn_ready = 0; - data_ready = 0; - - unique case(master) - INSN: insn_ready = bus_ready; - DATA: data_ready = bus_ready; - endcase - - bus_data_wr = data_data_wr; - unique case(next_master) - INSN: begin - bus_addr = insn_addr; - bus_write = 0; - bus_start = insn_start; - bus_data_be = 4'b1111; - bus_ex_lock = 0; - end - - DATA: begin - bus_addr = data_addr; - bus_write = data_write; - bus_start = data_start; - bus_data_be = data_data_be; - bus_ex_lock = data_ex_lock; - end - endcase - - if(hold_issue) begin - bus_addr = hold_addr; - bus_write = hold_write; - bus_start = 1; - bus_data_wr = hold_data_wr; - bus_data_be = hold_data_be; - bus_ex_lock = hold_ex_lock; - end - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - master <= INSN; - active <= 0; - - hold_addr <= 30'b0; - hold_start <= 0; - hold_write <= 0; - hold_data_wr <= 0; - hold_data_be <= 0; - hold_ex_lock <= 0; - end else begin - master <= next_master; - active <= bus_start || (active && !bus_ready); - - if(hold_free) - unique case(next_master) - INSN: begin - hold_addr <= data_addr; - hold_start <= data_start; - hold_write <= data_write; - hold_data_wr <= data_data_wr; - hold_data_be <= data_data_be; - hold_ex_lock <= data_ex_lock; - end - - DATA: begin - hold_addr <= insn_addr; - hold_start <= insn_start; - hold_write <= 0; - hold_data_be <= 4'b1111; - hold_ex_lock <= 0; - end - endcase - end - -endmodule diff --git a/rtl/core/mmu/fault.sv b/rtl/core/mmu/fault.sv deleted file mode 100644 index b33cec2..0000000 --- a/rtl/core/mmu/fault.sv +++ /dev/null @@ -1,83 +0,0 @@ -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_mmu_fault -( - input logic valid_entry, - skip_perms, - input word mmu_dac, - input mmu_domain domain, - input logic[1:0] ap, - input logic privileged, - write, - - output logic fault, - output mmu_fault_type fault_type -); - - mmu_domain_ctrl domain_ctrl; - - always_comb begin - unique case(domain) - 4'h0: domain_ctrl = mmu_dac[1:0]; - 4'h1: domain_ctrl = mmu_dac[3:2]; - 4'h2: domain_ctrl = mmu_dac[5:4]; - 4'h3: domain_ctrl = mmu_dac[7:6]; - 4'h4: domain_ctrl = mmu_dac[9:8]; - 4'h5: domain_ctrl = mmu_dac[11:10]; - 4'h6: domain_ctrl = mmu_dac[13:12]; - 4'h7: domain_ctrl = mmu_dac[15:14]; - 4'h8: domain_ctrl = mmu_dac[17:16]; - 4'h9: domain_ctrl = mmu_dac[19:18]; - 4'ha: domain_ctrl = mmu_dac[21:20]; - 4'hb: domain_ctrl = mmu_dac[23:22]; - 4'hc: domain_ctrl = mmu_dac[25:24]; - 4'hd: domain_ctrl = mmu_dac[27:26]; - 4'he: domain_ctrl = mmu_dac[29:28]; - 4'hf: domain_ctrl = mmu_dac[31:30]; - endcase - - fault = 0; - fault_type = `MMU_FAULT_ACCESS; - - if(!valid_entry) begin - fault = 1; - fault_type = `MMU_FAULT_WALK; - end else if(!skip_perms) begin - if(!domain_ctrl.allowed) begin - fault = 1; - fault_type = `MMU_FAULT_DOMAIN; - end else if(!domain_ctrl.manager) - /* Hay una diferencia importante entre lo que dicen los - * manuales y lo que al parecer pasa realmente. Según - * el source del kernel, 0b00 debe permitir lecturas - * desde modos privilegiados (PTE_SMALL_AP_UNO_SRO), - * lo cual corresponde al caso con S = 1 en la tabla B4-1 - * del ARM ARM. Por otro lado, el kernel nunca usa su propia - * definición de CR_S. Mi única explicación para que esto - * funcione es que los cores legacy tienen S = 1 en reset - * y a nadie nunca se le ocurrió revisar eso, o tal vez - * el manual está mal. - * - * Todo esto resulta en que, si se interpretan los bits AP - * como dice el manual de ARMv6, la página inmediatamente - * posterior a tabla de vectores altos del kernel provoque - * un prefetch abort (!!!) cuando los vectores saltan a esta, - * lo cual causa un bucle infinito de aborts a la primera IRQ. - */ - unique case(ap) - 2'b00: - fault = !privileged || write; - - 2'b01: - fault = !privileged; - - 2'b10: - fault = !privileged && write; - - 2'b11: ; - endcase - end - end - -endmodule diff --git a/rtl/core/mmu/format.sv b/rtl/core/mmu/format.sv deleted file mode 100644 index 3029b83..0000000 --- a/rtl/core/mmu/format.sv +++ /dev/null @@ -1,105 +0,0 @@ -`ifndef CORE_MMU_FORMAT_SV -`define CORE_MMU_FORMAT_SV - -typedef logic[17:0] mmu_base; -typedef logic[3:0] mmu_domain; - -`define MMU_L1_INDEX [29:18] -`define MMU_L1_FAULT 2'b00 -`define MMU_L1_PAGETABLE 2'b01 -`define MMU_L1_SECTION 2'b10 - -typedef struct packed -{ - logic[31:10] field10; - logic[9:9] imp; - logic[8:5] domain; - logic[4:4] sbz; - logic[3:2] field2; - logic[1:0] typ; -} mmu_l1_entry; - -typedef struct packed -{ - logic[31:10] base; - logic[9:9] imp; - logic[8:5] domain; - logic[4:2] sbz; - logic[1:0] typ; -} mmu_l1_pagetable; - -typedef struct packed -{ - logic[31:20] base; - logic[19:15] sbz0; - logic[14:12] tex; - logic[11:10] ap; - logic[9:9] imp; - logic[8:5] domain; - logic[4:4] sbz1; - logic[3:3] c; - logic[2:2] b; - logic[1:0] typ; -} mmu_l1_section; - -`define MMU_SECTION_INDEX [17:0] - -`define MMU_L2_INDEX [17:10] -`define MMU_L2_FAULT 2'b00 -`define MMU_L2_LARGE 2'b01 -`define MMU_L2_SMALL 2'b10 -`define MMU_L2_SMALLEXT 2'b11 - -typedef struct packed -{ - logic[31:16] base; - logic[15:15] sbz; - logic[14:12] tex; - logic[11:10] ap3; - logic[9:8] ap2; - logic[7:6] ap1; - logic[5:4] ap0; - logic[3:3] c; - logic[2:2] b; - logic[1:0] typ; -} mmu_l2_large; - -typedef struct packed -{ - logic[31:12] base; - logic[11:10] ap3; - logic[9:8] ap2; - logic[7:6] ap1; - logic[5:4] ap0; - logic[3:3] c; - logic[2:2] b; - logic[1:0] typ; -} mmu_l2_small; - -typedef struct packed -{ - logic[31:12] base; - logic[11:9] sbz; - logic[8:6] tex; - logic[5:4] ap; - logic[3:3] c; - logic[2:2] b; - logic[1:0] typ; -} mmu_l2_smallext; - -`define MMU_LARGE_INDEX [13:0] -`define MMU_SMALL_INDEX [9:0] - -typedef logic[1:0] mmu_fault_type; - -`define MMU_FAULT_WALK 2'b01 -`define MMU_FAULT_DOMAIN 2'b10 -`define MMU_FAULT_ACCESS 2'b11 - -typedef struct packed -{ - logic manager, - allowed; -} mmu_domain_ctrl; - -`endif diff --git a/rtl/core/mmu/mmu.sv b/rtl/core/mmu/mmu.sv deleted file mode 100644 index 22dfc3b..0000000 --- a/rtl/core/mmu/mmu.sv +++ /dev/null @@ -1,140 +0,0 @@ -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_mmu -( - input logic clk, - rst_n, - - input logic privileged, - mmu_enable /*verilator public*/, - input mmu_base mmu_ttbr /*verilator public*/, - input word mmu_dac, - - input logic bus_ready, - bus_ex_fail, - input word bus_data_rd, - data_data_wr, - input ptr insn_addr, - data_addr, - input logic insn_start, - data_start, - data_write, - data_ex_lock, - data_user, - input logic[3:0] data_data_be, - - output word bus_data_wr, - output logic[3:0] bus_data_be, - output ptr bus_addr, - output logic bus_start, - bus_write, - bus_ex_lock, - insn_ready, - insn_fault, - data_ready, - data_fault, - data_ex_fail, - output word insn_data_rd, - data_data_rd, - - output logic fault_register, - fault_page, - output ptr fault_addr, - output mmu_fault_type fault_type, - output mmu_domain fault_domain -); - - ptr iphys_addr, dphys_addr; - word iphys_data_rd, dphys_data_rd, dphys_data_wr; - logic[3:0] dphys_data_be; - - logic iphys_start, dphys_start, iphys_ready, dphys_ready, dphys_write, - dphys_ex_fail, dphys_ex_lock; - - assign fault_register = data_fault; - - core_mmu_pagewalk iwalk - ( - .core_addr(insn_addr), - .core_start(insn_start), - .core_write(0), - .core_ready(insn_ready), - .core_data_wr(0), - .core_data_be(0), - .core_data_rd(insn_data_rd), - .core_ex_fail(), - .core_ex_lock(0), - - .core_fault(insn_fault), - .core_fault_addr(), - .core_fault_page(), - .core_fault_type(), - .core_fault_domain(), - - .bus_addr(iphys_addr), - .bus_start(iphys_start), - .bus_write(), - .bus_ready(iphys_ready), - .bus_data_wr(), - .bus_data_be(), - .bus_data_rd(iphys_data_rd), - .bus_ex_fail(0), - .bus_ex_lock(), - - .* - ); - - core_mmu_pagewalk dwalk - ( - .core_addr(data_addr), - .core_start(data_start), - .core_write(data_write), - .core_ready(data_ready), - .core_data_wr(data_data_wr), - .core_data_be(data_data_be), - .core_data_rd(data_data_rd), - .core_ex_fail(data_ex_fail), - .core_ex_lock(data_ex_lock), - - .core_fault(data_fault), - .core_fault_addr(fault_addr), - .core_fault_page(fault_page), - .core_fault_type(fault_type), - .core_fault_domain(fault_domain), - - .bus_addr(dphys_addr), - .bus_start(dphys_start), - .bus_write(dphys_write), - .bus_ready(dphys_ready), - .bus_data_wr(dphys_data_wr), - .bus_data_be(dphys_data_be), - .bus_data_rd(dphys_data_rd), - .bus_ex_fail(dphys_ex_fail), - .bus_ex_lock(dphys_ex_lock), - - .privileged(privileged && !data_user), - .* - ); - - core_mmu_arbiter arbiter - ( - .insn_addr(iphys_addr), - .insn_start(iphys_start), - .insn_ready(iphys_ready), - .insn_data_rd(iphys_data_rd), - - .data_addr(dphys_addr), - .data_start(dphys_start), - .data_write(dphys_write), - .data_ready(dphys_ready), - .data_data_wr(dphys_data_wr), - .data_data_be(dphys_data_be), - .data_data_rd(dphys_data_rd), - .data_ex_fail(dphys_ex_fail), - .data_ex_lock(dphys_ex_lock), - - .* - ); - -endmodule diff --git a/rtl/core/mmu/pagewalk.sv b/rtl/core/mmu/pagewalk.sv deleted file mode 100644 index 70c932c..0000000 --- a/rtl/core/mmu/pagewalk.sv +++ /dev/null @@ -1,266 +0,0 @@ -`include "core/mmu/format.sv" -`include "core/uarch.sv" - -module core_mmu_pagewalk -( - input logic clk, - rst_n, - - input logic privileged, - mmu_enable, - input mmu_base mmu_ttbr, - input word mmu_dac, - - input logic bus_ready, - bus_ex_fail, - input word bus_data_rd, - - input ptr core_addr, - input word core_data_wr, - input logic[3:0] core_data_be, - input logic core_start, - core_write, - core_ex_lock, - - output ptr bus_addr, - output word bus_data_wr, - output logic[3:0] bus_data_be, - output logic bus_start, - bus_write, - bus_ex_lock, - - output word core_data_rd, - output logic core_ready, - core_ex_fail, - core_fault, - core_fault_page, - output ptr core_fault_addr, - output mmu_fault_type core_fault_type, - output mmu_domain core_fault_domain -); - - enum int unsigned - { - IDLE, - L1, - L2, - DATA, - FAULT - } state; - - logic access_fault, valid_entry, skip_perms; - logic[1:0] ap, entry_type; - mmu_domain domain, entry_domain; - mmu_fault_type access_fault_type; - - assign entry_type = bus_data_rd[1:0]; - assign core_fault_domain = domain; - - core_mmu_fault access_check - ( - .write(hold_write), - .fault(access_fault), - .domain(entry_domain), - .fault_type(access_fault_type), - .* - ); - - mmu_l1_entry l1; - assign l1 = bus_data_rd; - - mmu_l1_pagetable pagetable; - assign pagetable = bus_data_rd; - - mmu_l1_section section; - assign section = bus_data_rd; - - mmu_l2_large ptentry_large; - assign ptentry_large = bus_data_rd; - - mmu_l2_small ptentry_small; - assign ptentry_small = bus_data_rd; - - mmu_l2_smallext ptentry_smallext; - assign ptentry_smallext = bus_data_rd; - - ptr target; - word hold_data; - logic hold_write, hold_ex_lock; - logic[3:0] hold_be; - - always_comb begin - ap = 2'bxx; - skip_perms = 0; - valid_entry = 1; - entry_domain = domain; - - unique case(state) - L1: - unique case(entry_type) - `MMU_L1_PAGETABLE: begin - ap = 2'bxx; - skip_perms = 1; - end - - `MMU_L1_SECTION: begin - ap = section.ap; - entry_domain = l1.domain; - end - - // Tiny (1KiB wtf?) pages and supersections not supported - default: - valid_entry = 0; - endcase - - L2: - unique case(entry_type) - `MMU_L2_FAULT: - valid_entry = 0; - - `MMU_L2_LARGE: - //TODO: ap3-ap2 (también en L2_SMALL) - ap = ptentry_large.ap0; - - `MMU_L2_SMALL: - ap = ptentry_small.ap0; - - `MMU_L2_SMALLEXT: - ap = ptentry_smallext.ap; - endcase - - default: - valid_entry = 1'bx; - endcase - end - - always @(posedge clk or negedge rst_n) - if(!rst_n) begin - state <= IDLE; - target <= 0; - domain <= 0; - - hold_be <= 0; - hold_data <= 0; - hold_write <= 0; - hold_ex_lock <= 0; - - bus_addr <= 0; - bus_start <= 0; - bus_write <= 0; - bus_ex_lock <= 0; - bus_data_be <= 0; - bus_data_wr <= 0; - - core_ready <= 0; - core_fault <= 0; - core_ex_fail <= 0; - core_data_rd <= 0; - core_fault_page <= 0; - core_fault_addr <= 0; - core_fault_type <= 0; - end else begin - if(bus_start) - bus_start <= 0; - - if(core_ready) - core_ready <= 0; - - if(core_fault) - core_fault <= 0; - - unique case(state) - IDLE: - if(core_start) begin - bus_start <= 1; - - if(mmu_enable) begin - target <= core_addr; - hold_be <= core_data_be; - hold_data <= core_data_wr; - hold_write <= core_write; - hold_ex_lock <= core_ex_lock; - - state <= L1; - bus_addr <= {mmu_ttbr, core_addr `MMU_L1_INDEX}; - bus_write <= 0; - bus_ex_lock <= 0; - end else begin - state <= DATA; - bus_addr <= core_addr; - bus_write <= core_write; - bus_ex_lock <= core_ex_lock; - bus_data_wr <= core_data_wr; - bus_data_be <= core_data_be; - end - end - - L1: - if(bus_ready) begin - domain <= l1.domain; - - unique case(entry_type) - `MMU_L1_PAGETABLE: begin - state <= L2; - bus_addr <= {pagetable.base, target `MMU_L2_INDEX}; - end - - `MMU_L1_SECTION: begin - state <= DATA; - bus_addr <= {section.base, target `MMU_SECTION_INDEX}; - bus_write <= hold_write; - bus_ex_lock <= hold_ex_lock; - bus_data_wr <= hold_data; - bus_data_be <= hold_be; - end - - default: ; - endcase - end - - L2: - if(bus_ready) begin - state <= DATA; - - bus_write <= hold_write; - bus_ex_lock <= hold_ex_lock; - bus_data_wr <= hold_data; - bus_data_be <= hold_be; - - unique case(entry_type) - `MMU_L2_FAULT: ; - - `MMU_L2_LARGE: - bus_addr <= {ptentry_large.base, target `MMU_LARGE_INDEX}; - - `MMU_L2_SMALL, `MMU_L2_SMALLEXT: - bus_addr <= {ptentry_small.base, target `MMU_SMALL_INDEX}; - endcase - end - - DATA: - if(bus_ready) begin - state <= IDLE; - core_ready <= 1; - core_ex_fail <= bus_ex_fail; - core_data_rd <= bus_data_rd; - end - - FAULT: begin - state <= IDLE; - core_fault <= 1; - core_ready <= 1; - core_fault_addr <= target; - end - endcase - - if((state == L1 || state == L2) && bus_ready) begin - if(access_fault) begin - state <= FAULT; - core_fault_type <= access_fault_type; - core_fault_page <= state == L2; - end else - bus_start <= 1; - end - end - -endmodule diff --git a/rtl/core/mmu_format.sv b/rtl/core/mmu_format.sv new file mode 100644 index 0000000..3029b83 --- /dev/null +++ b/rtl/core/mmu_format.sv @@ -0,0 +1,105 @@ +`ifndef CORE_MMU_FORMAT_SV +`define CORE_MMU_FORMAT_SV + +typedef logic[17:0] mmu_base; +typedef logic[3:0] mmu_domain; + +`define MMU_L1_INDEX [29:18] +`define MMU_L1_FAULT 2'b00 +`define MMU_L1_PAGETABLE 2'b01 +`define MMU_L1_SECTION 2'b10 + +typedef struct packed +{ + logic[31:10] field10; + logic[9:9] imp; + logic[8:5] domain; + logic[4:4] sbz; + logic[3:2] field2; + logic[1:0] typ; +} mmu_l1_entry; + +typedef struct packed +{ + logic[31:10] base; + logic[9:9] imp; + logic[8:5] domain; + logic[4:2] sbz; + logic[1:0] typ; +} mmu_l1_pagetable; + +typedef struct packed +{ + logic[31:20] base; + logic[19:15] sbz0; + logic[14:12] tex; + logic[11:10] ap; + logic[9:9] imp; + logic[8:5] domain; + logic[4:4] sbz1; + logic[3:3] c; + logic[2:2] b; + logic[1:0] typ; +} mmu_l1_section; + +`define MMU_SECTION_INDEX [17:0] + +`define MMU_L2_INDEX [17:10] +`define MMU_L2_FAULT 2'b00 +`define MMU_L2_LARGE 2'b01 +`define MMU_L2_SMALL 2'b10 +`define MMU_L2_SMALLEXT 2'b11 + +typedef struct packed +{ + logic[31:16] base; + logic[15:15] sbz; + logic[14:12] tex; + logic[11:10] ap3; + logic[9:8] ap2; + logic[7:6] ap1; + logic[5:4] ap0; + logic[3:3] c; + logic[2:2] b; + logic[1:0] typ; +} mmu_l2_large; + +typedef struct packed +{ + logic[31:12] base; + logic[11:10] ap3; + logic[9:8] ap2; + logic[7:6] ap1; + logic[5:4] ap0; + logic[3:3] c; + logic[2:2] b; + logic[1:0] typ; +} mmu_l2_small; + +typedef struct packed +{ + logic[31:12] base; + logic[11:9] sbz; + logic[8:6] tex; + logic[5:4] ap; + logic[3:3] c; + logic[2:2] b; + logic[1:0] typ; +} mmu_l2_smallext; + +`define MMU_LARGE_INDEX [13:0] +`define MMU_SMALL_INDEX [9:0] + +typedef logic[1:0] mmu_fault_type; + +`define MMU_FAULT_WALK 2'b01 +`define MMU_FAULT_DOMAIN 2'b10 +`define MMU_FAULT_ACCESS 2'b11 + +typedef struct packed +{ + logic manager, + allowed; +} mmu_domain_ctrl; + +`endif diff --git a/rtl/core/mul.sv b/rtl/core/mul.sv deleted file mode 100644 index 19bbb9a..0000000 --- a/rtl/core/mul.sv +++ /dev/null @@ -1,64 +0,0 @@ -`include "core/uarch.sv" - -// Realiza la operación a * b + c = q -module core_mul -( - input logic clk, // clock, ya que es una máquina de estados - rst_n, - - input word a, // primer sumando - b, // segundo sumando - c_hi, // parte más significativa de c - c_lo, // parte menos significativa de c - input logic long_mul, // 1 si c es de 2 words, cualquier otro valor si c es de 1 word - add, // 1 si c se suma - sig, // 1 si a y b son signed - start, // 1 indica que se inicie la multiplicacion - - output word q_hi, // parte más significativa del resultado - q_lo, // parte menos significativa del resultado - output logic n, // no hay C ni V, ya que se dejan unaffected - z, - ready // 1 cuando la multiplicación está lista -); - - logic[1:0] wait_state; - dword c, q; - - assign ready = !start && wait_state == {$bits(wait_state){1'b0}}; - assign {q_hi, q_lo} = q; - assign n = long_mul ? q_hi[$bits(q_hi) - 1] : q_lo[$bits(q_lo) - 1]; - assign z = q_lo == 0 && (!long_mul || q_hi == 0); - - //TODO: no está probado cuantos ciclos ocupa esto una vez sintetizado - //TODO: trivio? - dsp_mul it - ( - .clock0(clk), - .aclr0(0), //TODO: parece ser active-high, así que no puede ir a rst_n - .ena0(start || !ready), - .dataa_0(a), - .datab_0(b), - .chainin(c), - .signa(sig), - .signb(sig), - .result(q) - ); - - always_comb - if(!add) - c = {$bits(c){1'b0}}; - else if(long_mul) - c = {c_hi, c_lo}; - else - c = {{$bits(word){sig && c_lo[$bits(c_lo) - 1]}}, c_lo}; - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) - wait_state <= 0; - else if(wait_state > {$bits(wait_state){1'b0}}) - wait_state <= wait_state - 1; - else if(start) - wait_state <= {$bits(wait_state){1'b1}}; - -endmodule diff --git a/rtl/core/porch/conds.sv b/rtl/core/porch/conds.sv deleted file mode 100644 index b8db1e7..0000000 --- a/rtl/core/porch/conds.sv +++ /dev/null @@ -1,47 +0,0 @@ -`include "core/decode/isa.sv" -`include "core/uarch.sv" - -module core_porch_conds -( - input word insn, - input psr_flags flags, - - output logic execute, - conditional, - undefined -); - - always_comb begin - undefined = 0; - conditional = 1; - - unique case(insn `FIELD_COND) - `COND_EQ: execute = flags.z; - `COND_NE: execute = ~flags.z; - `COND_HS: execute = flags.c; - `COND_LO: execute = ~flags.c; - `COND_MI: execute = flags.n; - `COND_PL: execute = ~flags.n; - `COND_VS: execute = flags.v; - `COND_VC: execute = ~flags.v; - `COND_HI: execute = flags.c & ~flags.z; - `COND_LS: execute = ~flags.c | flags.z; - `COND_GE: execute = flags.n ~^ flags.v; - `COND_LT: execute = flags.n ^ flags.v; - `COND_GT: execute = ~flags.z & (flags.n ~^ flags.v); - `COND_LE: execute = flags.z | (flags.n ^ flags.v); - - `COND_AL: begin - execute = 1; - conditional = 0; - end - - `COND_UD: begin - execute = 1'bx; - conditional = 1'bx; - undefined = 1; - end - endcase - end - -endmodule diff --git a/rtl/core/porch/porch.sv b/rtl/core/porch/porch.sv deleted file mode 100644 index 060ab91..0000000 --- a/rtl/core/porch/porch.sv +++ /dev/null @@ -1,57 +0,0 @@ -`include "core/uarch.sv" - -module core_porch -( - input logic clk, - rst_n, - flush, - stall, - input psr_flags flags, - - input word fetch_insn, - input logic fetch_nop, - fetch_abort, - input ptr fetch_insn_pc, - fetch_head, - input insn_decode fetch_dec, - - output word insn, - output ptr insn_pc, - output insn_decode dec, - output logic abort -); - - logic execute, conditional, undefined, nop; - insn_decode hold_dec; - - //FIXME: User mode puede hacer msr o mcr y saltare cualquier límite de seguridad - - always_comb begin - dec = hold_dec; - dec.ctrl.nop = nop; - dec.ctrl.execute = !flush && dec.ctrl.execute && execute && !nop && !abort; - dec.ctrl.undefined = !flush && (dec.ctrl.undefined || undefined); - dec.ctrl.conditional = !flush && (dec.ctrl.conditional || conditional); - end - - core_porch_conds conds - ( - .* - ); - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - nop <= 0; // Even though it is a NOP - insn <= `NOP; - abort <= 0; - insn_pc <= 0; - hold_dec <= {$bits(hold_dec){1'b0}}; - end else if(flush || !stall) begin - nop <= flush ? 1 : fetch_nop; - insn <= flush ? `NOP : fetch_insn; - abort <= flush ? 0 : fetch_abort; - insn_pc <= flush ? fetch_head : fetch_insn_pc; - hold_dec <= fetch_dec; - end - -endmodule diff --git a/rtl/core/psr.sv b/rtl/core/psr.sv deleted file mode 100644 index 7bbffe6..0000000 --- a/rtl/core/psr.sv +++ /dev/null @@ -1,172 +0,0 @@ -`include "core/uarch.sv" - -module core_psr -( - input logic clk, - rst_n, - write, - saved, - wr_flags, - wr_control, - escalating, - update_flags, - alu_v_valid, - input psr_flags alu_flags, - input word psr_wr, - - output psr_flags flags, - output psr_intmask mask, - output psr_mode mode, - output word cpsr_rd, - spsr_rd, - output logic privileged -); - - typedef struct packed - { - psr_flags flags; - psr_intmask mask; - psr_mode mode; - } psr_state; - - typedef struct packed - { - psr_flags nzcv; - logic q; - logic[1:0] reserved0; - logic j; - logic[3:0] reserved1, - ge; - logic[5:0] reserved2; - logic e; - logic a; - psr_intmask if_; - logic t; - psr_mode m; - } psr_word; - - psr_word cpsr_word /*verilator public*/, spsr_word, wr_word; - psr_flags next_flags; - psr_state cpsr, spsr, spsr_svc, spsr_abt, spsr_und, spsr_irq, spsr_fiq, - wr_state, wr_clean; - - assign mode = cpsr.mode; - assign mask = cpsr.mask; - assign flags = cpsr.flags; - assign wr_word = psr_wr; - assign cpsr_rd = cpsr_word; - assign spsr_rd = spsr_word; - assign privileged = |mode[3:0]; // Not user - assign {wr_state.flags, wr_state.mask, wr_state.mode} = {wr_word.nzcv, wr_word.if_, wr_word.m}; - -`ifdef VERILATOR - psr_word spsr_svc_word /*verilator public*/, - spsr_abt_word /*verilator public*/, - spsr_und_word /*verilator public*/, - spsr_fiq_word /*verilator public*/, - spsr_irq_word /*verilator public*/; - - always_comb begin - spsr_svc_word = {$bits(spsr_svc_word){1'b0}}; - spsr_abt_word = {$bits(spsr_abt_word){1'b0}}; - spsr_und_word = {$bits(spsr_und_word){1'b0}}; - spsr_irq_word = {$bits(spsr_irq_word){1'b0}}; - spsr_fiq_word = {$bits(spsr_fiq_word){1'b0}}; - - spsr_svc_word.a = 1; - spsr_abt_word.a = 1; - spsr_und_word.a = 1; - spsr_irq_word.a = 1; - spsr_fiq_word.a = 1; - - {spsr_svc_word.nzcv, spsr_svc_word.if_, spsr_svc_word.m} - = {spsr_svc.flags, spsr_svc.mask, spsr_svc.mode}; - - {spsr_abt_word.nzcv, spsr_abt_word.if_, spsr_abt_word.m} - = {spsr_abt.flags, spsr_abt.mask, spsr_abt.mode}; - - {spsr_und_word.nzcv, spsr_und_word.if_, spsr_und_word.m} - = {spsr_und.flags, spsr_und.mask, spsr_und.mode}; - - {spsr_irq_word.nzcv, spsr_irq_word.if_, spsr_irq_word.m} - = {spsr_irq.flags, spsr_irq.mask, spsr_irq.mode}; - - {spsr_fiq_word.nzcv, spsr_fiq_word.if_, spsr_fiq_word.m} - = {spsr_fiq.flags, spsr_fiq.mask, spsr_fiq.mode}; - end -`endif - - always_comb begin - next_flags = alu_flags; - if(!alu_v_valid) - next_flags.v = flags.v; - - unique case(mode) - `MODE_SVC: spsr = spsr_svc; - `MODE_ABT: spsr = spsr_abt; - `MODE_UND: spsr = spsr_und; - `MODE_IRQ: spsr = spsr_irq; - `MODE_FIQ: spsr = spsr_fiq; - default: spsr = cpsr; - endcase - - cpsr_word = {$bits(cpsr_word){1'b0}}; - spsr_word = {$bits(spsr_word){1'b0}}; - {cpsr_word.a, spsr_word.a} = 2'b11; - - {cpsr_word.nzcv, cpsr_word.if_, cpsr_word.m} = {flags, mask, mode}; - {spsr_word.nzcv, spsr_word.if_, spsr_word.m} = {spsr.flags, spsr.mask, spsr.mode}; - - wr_clean = wr_state; - unique case(wr_state.mode) - `MODE_USR, `MODE_FIQ, `MODE_IRQ, `MODE_SVC, - `MODE_ABT, `MODE_UND, `MODE_SYS: ; - - default: - wr_clean.mode = mode; - endcase - - if(!wr_flags) - wr_clean.flags = flags; - - if(!wr_control) begin - wr_clean.mask = mask; - wr_clean.mode = mode; - end - - if(mode == `MODE_USR && !escalating) begin - wr_clean.mask = mask; - wr_clean.mode = `MODE_USR; - end - end - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - cpsr.mode <= `MODE_SVC; - cpsr.flags <= 4'b0000; - cpsr.mask.i <= 1; - cpsr.mask.f <= 1; - - spsr_svc <= {$bits(spsr_svc){1'b0}}; - spsr_abt <= {$bits(spsr_svc){1'b0}}; - spsr_und <= {$bits(spsr_svc){1'b0}}; - spsr_irq <= {$bits(spsr_svc){1'b0}}; - spsr_fiq <= {$bits(spsr_svc){1'b0}}; - end else begin - if(!write) begin - if(update_flags) - cpsr.flags <= next_flags; - end else if(!saved) - cpsr <= wr_clean; - else - unique case(mode) - `MODE_SVC: spsr_svc <= wr_clean; - `MODE_ABT: spsr_abt <= wr_clean; - `MODE_UND: spsr_und <= wr_clean; - `MODE_IRQ: spsr_irq <= wr_clean; - `MODE_FIQ: spsr_fiq <= wr_clean; - default: ; - endcase - end - -endmodule diff --git a/rtl/core/regs/file.sv b/rtl/core/regs/file.sv deleted file mode 100644 index 2ba95e8..0000000 --- a/rtl/core/regs/file.sv +++ /dev/null @@ -1,51 +0,0 @@ -`include "core/uarch.sv" - -module core_reg_file -( - input logic clk, - rst_n, - - input psr_mode rd_mode, - input reg_num rd_r, - input reg_index wr_index, - input logic wr_enable, - wr_enable_file, - input word wr_value, - wr_current, - pc_word, - - output word rd_value -); - - // Ver comentario en uarch.sv - word file[`NUM_GPREGS] /*verilator public*/; - word rd_actual; - logic rd_pc, hold_rd_pc, forward; - reg_index rd_index; - - core_reg_map map_rd - ( - .r(rd_r), - .mode(rd_mode), - .is_pc(rd_pc), - .index(rd_index) - ); - - assign rd_value = hold_rd_pc ? pc_word : forward ? wr_current : rd_actual; - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - forward <= 0; - rd_actual <= 0; - hold_rd_pc <= 0; - end else begin - forward <= wr_enable && rd_index == wr_index; - hold_rd_pc <= rd_pc; - - if(wr_enable_file) - file[wr_index] <= wr_value; - - rd_actual <= file[rd_index]; - end - -endmodule diff --git a/rtl/core/regs/reg_map.sv b/rtl/core/regs/reg_map.sv deleted file mode 100644 index 11085d4..0000000 --- a/rtl/core/regs/reg_map.sv +++ /dev/null @@ -1,30 +0,0 @@ -`include "core/uarch.sv" - -module core_reg_map -( - input reg_num r, - input psr_mode mode, - output logic is_pc, - output reg_index index -); - - reg_index usr; - assign usr = {1'b0, r}; - - always_comb begin - index = 5'bxxxxx; - is_pc = r == `R15; - - if(~is_pc) - unique case(mode) - `MODE_USR, `MODE_SYS: index = usr; - `MODE_FIQ: index = r >= 8 ? usr + 7 : usr; - `MODE_IRQ: index = r >= 13 ? usr + 9 : usr; - `MODE_UND: index = r >= 13 ? usr + 11 : usr; - `MODE_ABT: index = r >= 13 ? usr + 13 : usr; - `MODE_SVC: index = r >= 13 ? usr + 15 : usr; - default: ; - endcase - end - -endmodule diff --git a/rtl/core/regs/regs.sv b/rtl/core/regs/regs.sv deleted file mode 100644 index f9cecad..0000000 --- a/rtl/core/regs/regs.sv +++ /dev/null @@ -1,69 +0,0 @@ -`include "core/uarch.sv" - -module core_regs -( - input logic clk, - rst_n, - - input reg_num rd_r_a, - rd_r_b, - wr_r, - input psr_mode rd_mode, - wr_mode, - input logic wr_enable, - input word wr_value, - input ptr pc_visible, - - output word rd_value_a, - rd_value_b, - wr_current, - output logic branch -); - - /* Las Cyclone V no tienen bloques de memoria con al menos dos puertos de - * lectura y uno de escritura (tres puertos), lo más que tienen son bloques - * de dos puertos en total. Podemos ponerle cinta a esto con dos copias - * sincronizadas del archivo de registros. - */ - - word pc_word; - logic wr_pc, wr_enable_file; - reg_index wr_index; - - assign pc_word = {pc_visible, 2'b00}; - assign wr_enable_file = wr_enable && !wr_pc; - - core_reg_file a - ( - .rd_r(rd_r_a), - .rd_value(rd_value_a), - .* - ); - - core_reg_file b - ( - .rd_r(rd_r_b), - .rd_value(rd_value_b), - .* - ); - - core_reg_map map_wr - ( - .r(wr_r), - .mode(wr_mode), - .is_pc(wr_pc), - .index(wr_index) - ); - - always_ff @(posedge clk or negedge rst_n) - if(!rst_n) begin - branch <= 0; - wr_current <= 0; - end else begin - if(wr_enable) - wr_current <= wr_value; - - branch <= wr_enable && wr_pc; - end - -endmodule diff --git a/rtl/core/shifter.sv b/rtl/core/shifter.sv deleted file mode 100644 index 96b8866..0000000 --- a/rtl/core/shifter.sv +++ /dev/null @@ -1,42 +0,0 @@ -`include "core/uarch.sv" - -module core_shifter -#(parameter W=16) -( - input shifter_control ctrl, - input logic[W - 1:0] base, - input logic[7:0] shift, - input logic c_in, - - output logic[W - 1:0] q, - output logic c -); - - localparam LOG = $clog2(W); - - logic[W - 1:0] q_no_c, q_shl, q_shr, q_ror; - logic[W:0] sign_mask; - logic c_shl, c_shr, c_ror; - - assign sign_mask = {(W + 1){ctrl.sign_extend & base[W - 1]}}; - assign {c_shl, q_shl} = {c_in, base} << shift; - assign {q_shr, c_shr} = {base, c_in} >> shift | (sign_mask & ~(sign_mask >> shift)); - - logic ror_cycle; - logic[LOG - 1:0] ror_shift; - logic[2 * W:0] ror_out; - - assign ror_shift = shift[LOG - 1:0]; - assign ror_cycle = |shift[7:LOG] & ~|ror_shift; - assign ror_out = {base, base, c_in} >> {ror_cycle, ror_shift}; - assign {q_ror, c_ror} = ror_out[W:0]; - - always_comb - if(ctrl.ror) - {c, q} = {c_ror, q_ror}; - else if(ctrl.shr) - {c, q} = {c_shr, q_shr[W - 1] | (ctrl.put_carry && c_in && shift != 0), q_shr[W - 2:0]}; - else - {c, q} = {c_shl, q_shl}; - -endmodule diff --git a/rtl/perf/link.sv b/rtl/perf/link.sv deleted file mode 100644 index 323af45..0000000 --- a/rtl/perf/link.sv +++ /dev/null @@ -1,181 +0,0 @@ -`include "cache/defs.sv" - -module perf_link -( - input logic clk, - rst_n, - - input logic in_left_valid, - input ring_req in_left, - output logic in_left_ready, - - input logic in_right_valid, - input ring_req in_right, - input logic in_right_ready, - - input logic out_left_ready, - output ring_req out_left, - output logic out_left_valid, - - input line_ptr local_address, - input logic local_read, - local_write, - input line local_writedata, - input line_be local_byteenable, - output logic local_waitrequest, - output line local_readdata, - - input logic mem_waitrequest, - input line mem_readdata, - output word mem_address, - output logic mem_read, - mem_write, - output line mem_writedata, - output line_be mem_byteenable, - - input logic clear, - input logic[3:0] address, - output word readdata -); - - logic snoop_left_ready, snoop_left_valid, snoop_right_ready, snoop_right_valid, - snoop_read, snoop_write, snoop_waitrequest, cached; - - addr_bits snoop_addr_bits; - perf_sample snoop_left, snoop_right; - - word reads, writes, ring_reads, ring_invals, ring_read_invals, ring_replies, ring_forwards, - io_reads, io_writes, snoop_address; - - hword mem_cycles, mem_cycles_hold, ring_cycles, min_ring_cycles, max_ring_cycles, - min_read_cycles, max_read_cycles, min_write_cycles, max_write_cycles; - - perf_snoop snoop - ( - .* - ); - - assign cached = snoop_addr_bits.io == `IO_CACHED; - assign mem_cycles = mem_cycles_hold + 1; - assign snoop_addr_bits = snoop_address; - - always_comb - if (!address[3]) unique case (address[2:0]) - 3'b000: readdata = reads; - 3'b001: readdata = writes; - 3'b010: readdata = {max_read_cycles, min_read_cycles}; - 3'b011: readdata = {max_write_cycles, min_write_cycles}; - 3'b100: readdata = ring_reads; - 3'b101: readdata = ring_invals; - 3'b110: readdata = ring_read_invals; - 3'b111: readdata = ring_replies; - endcase else unique case (address[1:0]) - 2'b00: readdata = ring_forwards; - 2'b01: readdata = {max_ring_cycles, min_ring_cycles}; - 2'b10: readdata = io_reads; - 2'b11: readdata = io_writes; - endcase - - always @(posedge clk or negedge rst_n) - if (!rst_n) begin - reads <= 0; - writes <= 0; - io_reads <= 0; - io_writes <= 0; - - min_ring_cycles <= 0; - max_ring_cycles <= 0; - min_read_cycles <= 0; - max_read_cycles <= 0; - min_write_cycles <= 0; - max_write_cycles <= 0; - - ring_reads <= 0; - ring_invals <= 0; - ring_replies <= 0; - ring_forwards <= 0; - ring_read_invals <= 0; - - mem_cycles_hold <= 0; - end else begin - ring_cycles <= ring_cycles + 1; - - if (mem_read || mem_write) - mem_cycles_hold <= mem_cycles; - - if ((mem_read || mem_write) && !mem_waitrequest) begin - mem_cycles_hold <= 0; - - if (!cached) begin - if (mem_write) - io_writes <= io_writes + 1; - else - io_reads <= io_reads + 1; - end else if (mem_write) begin - writes <= writes + 1; - - if (min_write_cycles == 0 || mem_cycles_hold < min_write_cycles) - min_write_cycles <= mem_cycles; - - if (mem_cycles_hold >= max_write_cycles) - max_write_cycles <= mem_cycles; - end else begin - reads <= reads + 1; - - if (min_read_cycles == 0 || mem_cycles_hold < min_read_cycles) - min_read_cycles <= mem_cycles; - - if (mem_cycles_hold >= max_read_cycles) - max_read_cycles <= mem_cycles; - end - end - - if (snoop_left_valid && snoop_left_ready && snoop_left.ttl == `TTL_END) begin - if (snoop_left.reply) - ring_replies <= ring_replies + 1; - - if (min_ring_cycles == 0 || ring_cycles < min_ring_cycles) - min_ring_cycles <= ring_cycles; - - if (ring_cycles > max_ring_cycles) - max_ring_cycles <= ring_cycles; - end - - if (snoop_right_valid && snoop_right_ready) begin - if (snoop_right.ttl == `TTL_MAX) begin - ring_cycles <= 1; - - if (snoop_right.read && !snoop_right.inval) - ring_reads <= ring_reads + 1; - - if (!snoop_right.read && snoop_right.inval) - ring_invals <= ring_invals + 1; - - if (snoop_right.read && snoop_right.inval) - ring_read_invals <= ring_read_invals + 1; - end else - ring_forwards <= ring_forwards + 1; - end - - if (clear) begin - reads <= 0; - writes <= 0; - io_reads <= 0; - io_writes <= 0; - - min_ring_cycles <= 0; - max_ring_cycles <= 0; - min_read_cycles <= 0; - max_read_cycles <= 0; - min_write_cycles <= 0; - max_write_cycles <= 0; - - ring_reads <= 0; - ring_invals <= 0; - ring_replies <= 0; - ring_forwards <= 0; - ring_read_invals <= 0; - end - end - -endmodule diff --git a/rtl/perf/perf_link.sv b/rtl/perf/perf_link.sv new file mode 100644 index 0000000..323af45 --- /dev/null +++ b/rtl/perf/perf_link.sv @@ -0,0 +1,181 @@ +`include "cache/defs.sv" + +module perf_link +( + input logic clk, + rst_n, + + input logic in_left_valid, + input ring_req in_left, + output logic in_left_ready, + + input logic in_right_valid, + input ring_req in_right, + input logic in_right_ready, + + input logic out_left_ready, + output ring_req out_left, + output logic out_left_valid, + + input line_ptr local_address, + input logic local_read, + local_write, + input line local_writedata, + input line_be local_byteenable, + output logic local_waitrequest, + output line local_readdata, + + input logic mem_waitrequest, + input line mem_readdata, + output word mem_address, + output logic mem_read, + mem_write, + output line mem_writedata, + output line_be mem_byteenable, + + input logic clear, + input logic[3:0] address, + output word readdata +); + + logic snoop_left_ready, snoop_left_valid, snoop_right_ready, snoop_right_valid, + snoop_read, snoop_write, snoop_waitrequest, cached; + + addr_bits snoop_addr_bits; + perf_sample snoop_left, snoop_right; + + word reads, writes, ring_reads, ring_invals, ring_read_invals, ring_replies, ring_forwards, + io_reads, io_writes, snoop_address; + + hword mem_cycles, mem_cycles_hold, ring_cycles, min_ring_cycles, max_ring_cycles, + min_read_cycles, max_read_cycles, min_write_cycles, max_write_cycles; + + perf_snoop snoop + ( + .* + ); + + assign cached = snoop_addr_bits.io == `IO_CACHED; + assign mem_cycles = mem_cycles_hold + 1; + assign snoop_addr_bits = snoop_address; + + always_comb + if (!address[3]) unique case (address[2:0]) + 3'b000: readdata = reads; + 3'b001: readdata = writes; + 3'b010: readdata = {max_read_cycles, min_read_cycles}; + 3'b011: readdata = {max_write_cycles, min_write_cycles}; + 3'b100: readdata = ring_reads; + 3'b101: readdata = ring_invals; + 3'b110: readdata = ring_read_invals; + 3'b111: readdata = ring_replies; + endcase else unique case (address[1:0]) + 2'b00: readdata = ring_forwards; + 2'b01: readdata = {max_ring_cycles, min_ring_cycles}; + 2'b10: readdata = io_reads; + 2'b11: readdata = io_writes; + endcase + + always @(posedge clk or negedge rst_n) + if (!rst_n) begin + reads <= 0; + writes <= 0; + io_reads <= 0; + io_writes <= 0; + + min_ring_cycles <= 0; + max_ring_cycles <= 0; + min_read_cycles <= 0; + max_read_cycles <= 0; + min_write_cycles <= 0; + max_write_cycles <= 0; + + ring_reads <= 0; + ring_invals <= 0; + ring_replies <= 0; + ring_forwards <= 0; + ring_read_invals <= 0; + + mem_cycles_hold <= 0; + end else begin + ring_cycles <= ring_cycles + 1; + + if (mem_read || mem_write) + mem_cycles_hold <= mem_cycles; + + if ((mem_read || mem_write) && !mem_waitrequest) begin + mem_cycles_hold <= 0; + + if (!cached) begin + if (mem_write) + io_writes <= io_writes + 1; + else + io_reads <= io_reads + 1; + end else if (mem_write) begin + writes <= writes + 1; + + if (min_write_cycles == 0 || mem_cycles_hold < min_write_cycles) + min_write_cycles <= mem_cycles; + + if (mem_cycles_hold >= max_write_cycles) + max_write_cycles <= mem_cycles; + end else begin + reads <= reads + 1; + + if (min_read_cycles == 0 || mem_cycles_hold < min_read_cycles) + min_read_cycles <= mem_cycles; + + if (mem_cycles_hold >= max_read_cycles) + max_read_cycles <= mem_cycles; + end + end + + if (snoop_left_valid && snoop_left_ready && snoop_left.ttl == `TTL_END) begin + if (snoop_left.reply) + ring_replies <= ring_replies + 1; + + if (min_ring_cycles == 0 || ring_cycles < min_ring_cycles) + min_ring_cycles <= ring_cycles; + + if (ring_cycles > max_ring_cycles) + max_ring_cycles <= ring_cycles; + end + + if (snoop_right_valid && snoop_right_ready) begin + if (snoop_right.ttl == `TTL_MAX) begin + ring_cycles <= 1; + + if (snoop_right.read && !snoop_right.inval) + ring_reads <= ring_reads + 1; + + if (!snoop_right.read && snoop_right.inval) + ring_invals <= ring_invals + 1; + + if (snoop_right.read && snoop_right.inval) + ring_read_invals <= ring_read_invals + 1; + end else + ring_forwards <= ring_forwards + 1; + end + + if (clear) begin + reads <= 0; + writes <= 0; + io_reads <= 0; + io_writes <= 0; + + min_ring_cycles <= 0; + max_ring_cycles <= 0; + min_read_cycles <= 0; + max_read_cycles <= 0; + min_write_cycles <= 0; + max_write_cycles <= 0; + + ring_reads <= 0; + ring_invals <= 0; + ring_replies <= 0; + ring_forwards <= 0; + ring_read_invals <= 0; + end + end + +endmodule diff --git a/rtl/perf/perf_snoop.sv b/rtl/perf/perf_snoop.sv new file mode 100644 index 0000000..e98153e --- /dev/null +++ b/rtl/perf/perf_snoop.sv @@ -0,0 +1,129 @@ +`include "cache/defs.sv" + +module perf_snoop +( + input logic clk, + rst_n, + + input logic in_left_valid, + input ring_req in_left, + output logic in_left_ready, + + input logic out_left_ready, + output ring_req out_left, + output logic out_left_valid, + + input logic in_right_valid, + input ring_req in_right, + input logic in_right_ready, + + input line_ptr local_address, + input logic local_read, + local_write, + input line local_writedata, + input line_be local_byteenable, + output logic local_waitrequest, + output line local_readdata, + + input logic mem_waitrequest, + input line mem_readdata, + output word mem_address, + output logic mem_read, + mem_write, + output line mem_writedata, + output line_be mem_byteenable, + + output logic snoop_left_ready, + snoop_left_valid, + snoop_right_ready, + snoop_right_valid, + snoop_read, + snoop_write, + snoop_waitrequest, + output word snoop_address, + output perf_sample snoop_left, + snoop_right +); + + word hold_address; + logic hold_left_ready, hold_left_valid, hold_right_ready, hold_right_valid, + hold_read, hold_write, hold_waitrequest; + + perf_sample hold_left, hold_right; + + // out_right es driveado por las mismas líneas debido al anillo + assign in_left_ready = out_left_ready; + assign out_left = in_left; + assign out_left_valid = in_left_valid; + + assign mem_read = local_read; + assign mem_write = local_write; + assign mem_address = {local_address, 4'b0000}; + assign mem_writedata = local_writedata; + assign mem_byteenable = local_byteenable; + assign local_readdata = mem_readdata; + assign local_waitrequest = mem_waitrequest; + + always @(posedge clk or negedge rst_n) + if (!rst_n) begin + hold_read <= 0; + hold_write <= 0; + hold_waitrequest <= 0; + + hold_left_ready <= 0; + hold_left_valid <= 0; + hold_right_ready <= 0; + hold_right_valid <= 0; + + snoop_read <= 0; + snoop_write <= 0; + snoop_waitrequest <= 0; + + snoop_left_ready <= 0; + snoop_left_valid <= 0; + snoop_right_ready <= 0; + snoop_right_valid <= 0; + end else begin + /* La idea aquí es aligerar el trabajo del fitter, ya que perf_monitor + * muestrea el anillo completo, por lo que su span de área es + * potencialmente grande. + */ + + hold_read <= mem_read; + hold_write <= mem_write; + hold_waitrequest <= mem_waitrequest; + + hold_left_ready <= in_left_ready; + hold_left_valid <= in_left_valid; + hold_right_ready <= in_right_ready; + hold_right_valid <= in_right_valid; + + snoop_read <= hold_read; + snoop_write <= hold_write; + snoop_waitrequest <= hold_waitrequest; + + snoop_left_ready <= hold_left_ready; + snoop_left_valid <= hold_left_valid; + snoop_right_ready <= hold_right_ready; + snoop_right_valid <= hold_right_valid; + end + + always @(posedge clk) begin + hold_left.ttl <= in_left.ttl; + hold_left.read <= in_left.read; + hold_left.inval <= in_left.inval; + hold_left.reply <= in_left.reply; + + hold_right.ttl <= in_right.ttl; + hold_right.read <= in_right.read; + hold_right.inval <= in_right.inval; + hold_right.reply <= in_right.reply; + + snoop_left <= hold_left; + snoop_right <= hold_right; + + hold_address <= mem_address; + snoop_address <= hold_address; + end + +endmodule diff --git a/rtl/perf/snoop.sv b/rtl/perf/snoop.sv deleted file mode 100644 index e98153e..0000000 --- a/rtl/perf/snoop.sv +++ /dev/null @@ -1,129 +0,0 @@ -`include "cache/defs.sv" - -module perf_snoop -( - input logic clk, - rst_n, - - input logic in_left_valid, - input ring_req in_left, - output logic in_left_ready, - - input logic out_left_ready, - output ring_req out_left, - output logic out_left_valid, - - input logic in_right_valid, - input ring_req in_right, - input logic in_right_ready, - - input line_ptr local_address, - input logic local_read, - local_write, - input line local_writedata, - input line_be local_byteenable, - output logic local_waitrequest, - output line local_readdata, - - input logic mem_waitrequest, - input line mem_readdata, - output word mem_address, - output logic mem_read, - mem_write, - output line mem_writedata, - output line_be mem_byteenable, - - output logic snoop_left_ready, - snoop_left_valid, - snoop_right_ready, - snoop_right_valid, - snoop_read, - snoop_write, - snoop_waitrequest, - output word snoop_address, - output perf_sample snoop_left, - snoop_right -); - - word hold_address; - logic hold_left_ready, hold_left_valid, hold_right_ready, hold_right_valid, - hold_read, hold_write, hold_waitrequest; - - perf_sample hold_left, hold_right; - - // out_right es driveado por las mismas líneas debido al anillo - assign in_left_ready = out_left_ready; - assign out_left = in_left; - assign out_left_valid = in_left_valid; - - assign mem_read = local_read; - assign mem_write = local_write; - assign mem_address = {local_address, 4'b0000}; - assign mem_writedata = local_writedata; - assign mem_byteenable = local_byteenable; - assign local_readdata = mem_readdata; - assign local_waitrequest = mem_waitrequest; - - always @(posedge clk or negedge rst_n) - if (!rst_n) begin - hold_read <= 0; - hold_write <= 0; - hold_waitrequest <= 0; - - hold_left_ready <= 0; - hold_left_valid <= 0; - hold_right_ready <= 0; - hold_right_valid <= 0; - - snoop_read <= 0; - snoop_write <= 0; - snoop_waitrequest <= 0; - - snoop_left_ready <= 0; - snoop_left_valid <= 0; - snoop_right_ready <= 0; - snoop_right_valid <= 0; - end else begin - /* La idea aquí es aligerar el trabajo del fitter, ya que perf_monitor - * muestrea el anillo completo, por lo que su span de área es - * potencialmente grande. - */ - - hold_read <= mem_read; - hold_write <= mem_write; - hold_waitrequest <= mem_waitrequest; - - hold_left_ready <= in_left_ready; - hold_left_valid <= in_left_valid; - hold_right_ready <= in_right_ready; - hold_right_valid <= in_right_valid; - - snoop_read <= hold_read; - snoop_write <= hold_write; - snoop_waitrequest <= hold_waitrequest; - - snoop_left_ready <= hold_left_ready; - snoop_left_valid <= hold_left_valid; - snoop_right_ready <= hold_right_ready; - snoop_right_valid <= hold_right_valid; - end - - always @(posedge clk) begin - hold_left.ttl <= in_left.ttl; - hold_left.read <= in_left.read; - hold_left.inval <= in_left.inval; - hold_left.reply <= in_left.reply; - - hold_right.ttl <= in_right.ttl; - hold_right.read <= in_right.read; - hold_right.inval <= in_right.inval; - hold_right.reply <= in_right.reply; - - snoop_left <= hold_left; - snoop_right <= hold_right; - - hold_address <= mem_address; - snoop_address <= hold_address; - end - -endmodule diff --git a/rtl/smp/pe.sv b/rtl/smp/pe.sv deleted file mode 100644 index 5c675ee..0000000 --- a/rtl/smp/pe.sv +++ /dev/null @@ -1,53 +0,0 @@ -module smp_pe -#(parameter IS_BSP=0) -( - input logic clk, - rst_n, - - input logic write, - input logic[7:0] writedata, - output logic[7:0] readdata, - - input logic cpu_alive, - cpu_halted, - breakpoint, - - output logic halt, - step -); - - struct packed - { - logic step, halt, run; - } req; - - struct packed - { - logic alive, breakpoint, cpu_halted; - } status, status_out; - - assign req = writedata[$bits(req) - 1:0]; - assign readdata = {{(8 - $bits(status_out)){1'b0}}, status_out}; - - always_comb begin - status_out = status; - status_out.alive = cpu_alive; - end - - always @(posedge clk or negedge rst_n) - if (!rst_n) begin - halt <= IS_BSP ? 0 : 1; // Boot es single-core - step <= 0; - status <= {($bits(status)){1'b0}}; - end else begin - status.breakpoint <= breakpoint; - status.cpu_halted <= cpu_halted; - - //Se hace halt hasta el siguiente ciclo después de que se - //solicita el breakpoint - step <= (step && !breakpoint) || (req.step && write); - halt <= (halt || breakpoint || (req.halt && write)) - && !((req.run || req.step) && write); - end - -endmodule diff --git a/rtl/smp/smp_pe.sv b/rtl/smp/smp_pe.sv new file mode 100644 index 0000000..5c675ee --- /dev/null +++ b/rtl/smp/smp_pe.sv @@ -0,0 +1,53 @@ +module smp_pe +#(parameter IS_BSP=0) +( + input logic clk, + rst_n, + + input logic write, + input logic[7:0] writedata, + output logic[7:0] readdata, + + input logic cpu_alive, + cpu_halted, + breakpoint, + + output logic halt, + step +); + + struct packed + { + logic step, halt, run; + } req; + + struct packed + { + logic alive, breakpoint, cpu_halted; + } status, status_out; + + assign req = writedata[$bits(req) - 1:0]; + assign readdata = {{(8 - $bits(status_out)){1'b0}}, status_out}; + + always_comb begin + status_out = status; + status_out.alive = cpu_alive; + end + + always @(posedge clk or negedge rst_n) + if (!rst_n) begin + halt <= IS_BSP ? 0 : 1; // Boot es single-core + step <= 0; + status <= {($bits(status)){1'b0}}; + end else begin + status.breakpoint <= breakpoint; + status.cpu_halted <= cpu_halted; + + //Se hace halt hasta el siguiente ciclo después de que se + //solicita el breakpoint + step <= (step && !breakpoint) || (req.step && write); + halt <= (halt || breakpoint || (req.halt && write)) + && !((req.run || req.step) && write); + end + +endmodule -- cgit v1.2.3