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
|