| 1 |
14 |
Agner |
//////////////////////////////////////////////////////////////////////////////////
|
| 2 |
|
|
// Engineer: Agner Fog
|
| 3 |
|
|
//
|
| 4 |
|
|
// Create Date: 2020-05-05
|
| 5 |
|
|
// Last modified: 2021-08-02
|
| 6 |
|
|
// Module Name: code_cache
|
| 7 |
|
|
// Project Name: ForwardCom soft core
|
| 8 |
|
|
// Target Devices: Artix 7
|
| 9 |
|
|
// Tool Versions: Vivado v. 2020.1
|
| 10 |
|
|
// License: CERN-OHL-W v. 2 or later
|
| 11 |
|
|
// Description: on-chip code memory or code cache
|
| 12 |
|
|
//
|
| 13 |
|
|
//////////////////////////////////////////////////////////////////////////////////
|
| 14 |
|
|
`include "defines.vh"
|
| 15 |
|
|
|
| 16 |
|
|
// It takes two clock cycles to fetch data from on-chip ram,
|
| 17 |
|
|
// Attempts to fetch in one cycle, using negedge or latch failed for timing reasons
|
| 18 |
|
|
|
| 19 |
|
|
|
| 20 |
|
|
// code memory, 1024*64 bits,
|
| 21 |
|
|
module code_memory (
|
| 22 |
|
|
input clock, // clock
|
| 23 |
|
|
input clock_enable, // clock enable. Used when single-stepping
|
| 24 |
|
|
input read_enable, // read enable when fetching code
|
| 25 |
|
|
input [7:0] write_enable, // write enable for each byte separately when writing code. must be 0x0F or 0xF0 or 0xFF
|
| 26 |
|
|
input [`COMMON_ADDR_WIDTH-1:0] write_addr_in,// Address lines when writing to code memory
|
| 27 |
|
|
input [63:0] write_data_in, // Data lines when writing to code memory
|
| 28 |
|
|
input [`CODE_ADDR_WIDTH-2:0] read_addr_in, // Address for reading from code memory
|
| 29 |
|
|
output reg [`CODE_DATA_WIDTH-1:0] data_out, // Data out
|
| 30 |
|
|
|
| 31 |
|
|
// outputs for debugger:
|
| 32 |
|
|
output reg [31:0] debug_out // debug information
|
| 33 |
|
|
);
|
| 34 |
|
|
|
| 35 |
|
|
// code ram
|
| 36 |
|
|
reg [`CODE_DATA_WIDTH-1:0] ram[0:(2**(`CODE_ADDR_WIDTH-1)-1)];
|
| 37 |
|
|
// (attempt to split this into 32-bit lines failed to implement as ram block)
|
| 38 |
|
|
|
| 39 |
|
|
logic [`COMMON_ADDR_WIDTH-4:0] write_address_hi;
|
| 40 |
|
|
//logic [`DATA_ADDR_WIDTH-4:0] write_address_hi;
|
| 41 |
|
|
//logic [2:0] address_lo; // not used
|
| 42 |
|
|
logic write_address_valid;
|
| 43 |
|
|
|
| 44 |
|
|
always_comb begin
|
| 45 |
|
|
// write_address_hi = write_addr_in[`COMMON_ADDR_WIDTH-1:3] - {1'b1,`CODE_ADDR_START'b0}; // index to 64-bit lines
|
| 46 |
|
|
write_address_hi = write_addr_in[`COMMON_ADDR_WIDTH-1:3] - {1'b1,{(`CODE_ADDR_START-3){1'b0}}}; // index to 64-bit lines
|
| 47 |
|
|
write_address_valid = write_addr_in[`COMMON_ADDR_WIDTH-1:`CODE_ADDR_START] != 0; // code address space
|
| 48 |
|
|
end
|
| 49 |
|
|
|
| 50 |
|
|
/*
|
| 51 |
|
|
Calculation of loader address:
|
| 52 |
|
|
Code memory starts at address 2**CODE_ADDR_START = 32kB = 0x8000
|
| 53 |
|
|
Code memory size = 2**(CODE_ADDR_WIDTH+2) = 64kB = 0x10000
|
| 54 |
|
|
Code memory end = code memory start + code memory size = 0x18000
|
| 55 |
|
|
Max loader size = 2kB = 0x800 bytes
|
| 56 |
|
|
Loader start address = code memory end - max loader size
|
| 57 |
|
|
Each line in code ram is CODE_DATA_WIDTH = 64 bits = 8 bytes
|
| 58 |
|
|
Loader start line = (code memory size - max loader size) / line size
|
| 59 |
|
|
*/
|
| 60 |
|
|
parameter max_loader_size = `MAX_LOADER_SIZE << 2; // loader size in bytes
|
| 61 |
|
|
parameter code_memory_start = 2**`CODE_ADDR_START;
|
| 62 |
|
|
parameter code_memory_size = 2**(`CODE_ADDR_WIDTH+2);
|
| 63 |
|
|
parameter code_memory_end = code_memory_start + code_memory_size;
|
| 64 |
|
|
parameter loader_start_address = code_memory_end - max_loader_size;
|
| 65 |
|
|
parameter loader_start_relative = code_memory_size - max_loader_size;
|
| 66 |
|
|
parameter loader_start_line = loader_start_relative / (`CODE_DATA_WIDTH >> 3);
|
| 67 |
|
|
|
| 68 |
|
|
generate if (`LOADER_FILE != "")
|
| 69 |
|
|
initial begin
|
| 70 |
|
|
// insert loader code
|
| 71 |
|
|
$readmemh(`LOADER_FILE, ram, loader_start_line);
|
| 72 |
|
|
end
|
| 73 |
|
|
endgenerate
|
| 74 |
|
|
|
| 75 |
|
|
|
| 76 |
|
|
// code ram read and write process
|
| 77 |
|
|
always_ff @(posedge clock) if (clock_enable) begin
|
| 78 |
|
|
|
| 79 |
|
|
// Write data to code RAM when loading program code
|
| 80 |
|
|
if (write_address_valid) begin // write address is in code section
|
| 81 |
|
|
if (write_enable[0]) begin
|
| 82 |
|
|
ram[write_address_hi][31:0] <= write_data_in[31:0];
|
| 83 |
|
|
end
|
| 84 |
|
|
if (write_enable[4]) begin
|
| 85 |
|
|
ram[write_address_hi][63:32] <= write_data_in[63:32];
|
| 86 |
|
|
end
|
| 87 |
|
|
end
|
| 88 |
|
|
|
| 89 |
|
|
// Read from code ram when executing
|
| 90 |
|
|
if (read_enable) begin
|
| 91 |
|
|
data_out <= ram[read_addr_in];
|
| 92 |
|
|
end
|
| 93 |
|
|
|
| 94 |
|
|
// Output for debugger
|
| 95 |
|
|
debug_out[23:0] <= write_address_hi;
|
| 96 |
|
|
debug_out[28] <= write_address_valid;
|
| 97 |
|
|
|
| 98 |
|
|
end
|
| 99 |
|
|
|
| 100 |
|
|
endmodule
|