Skip to content

Commit 0d447e1

Browse files
committed
Fix slink_32b_elf_preload
1 parent f3306d2 commit 0d447e1

File tree

1 file changed

+98
-40
lines changed

1 file changed

+98
-40
lines changed

target/sim/src/tb_picobello_top.sv

Lines changed: 98 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -62,56 +62,114 @@ module tb_picobello_top;
6262
$display("[JTAG] Preload complete");
6363
endtask
6464

65+
// Handles misalignments and 4KiB crossings
66+
task automatic slink_write_generic(
67+
input addr_t addr,
68+
input longint size,
69+
ref byte bytes []
70+
);
71+
// Using `slink_write_beats`, writes must be beat-aligned and beat-sized (strobing is not
72+
// possible). If we have a misaligned transfer of arbitrary size we may have at most two
73+
// incomplete beats (start and end) and one misaligned beat (start). In case of an incomplete
74+
// beat we read-modify-write the full beat.
75+
76+
// Burst and beat geometry
77+
const int beat_bytes = fix.vip.AxiStrbWidth;
78+
const int beat_mask = beat_bytes - 1;
79+
const int SlinkBurstBeats = fix.vip.SlinkBurstBytes / beat_bytes;
80+
81+
// Iterate beat-by-beat over the address range [addr, addr+size)
82+
addr_t first_aligned = addr_t'(addr) & ~addr_t'(beat_mask);
83+
addr_t end_addr = addr_t'(addr + size);
84+
addr_t last_aligned = addr_t'((end_addr - 1) & ~addr_t'(beat_mask));
85+
86+
// Running index into bytes[]: "how many bytes have we already consumed?"
87+
longint base_idx = 0;
88+
89+
// Accumulate beats for current 4 KiB page
90+
addr_t batch_addr = first_aligned;
91+
axi_data_t out[$]; out = {};
92+
93+
for (addr_t beat_addr = first_aligned; beat_addr <= last_aligned; beat_addr += beat_bytes) begin
94+
addr_t next_addr;
95+
bit crosses_4k_next, exceeds_burst_length, last_beat_in_section;
96+
97+
// Window of the current beat that has to be written
98+
int start_off = (beat_addr == first_aligned) ? int'(addr & beat_mask) : 0;
99+
int end_off_excl = (beat_addr == last_aligned) ? int'(end_addr - last_aligned) : beat_bytes;
100+
int win_len = end_off_excl - start_off;
101+
102+
// Compose beat
103+
axi_data_t beat = '0;
104+
if (win_len == beat_bytes && start_off == 0) begin
105+
// FULL BEAT: write directly, no RMW
106+
for (int e = 0; e < beat_bytes; e++) begin
107+
beat[8*e +: 8] = bytes[base_idx + e];
108+
end
109+
end else begin
110+
// PARTIAL BEAT: RMW
111+
axi_data_t rd[$];
112+
fix.vip.slink_read_beats(beat_addr, fix.vip.AxiStrbBits, 0, rd);
113+
beat = rd[0];
114+
for (int i = 0; i < win_len; i++) begin
115+
beat[8*(start_off + i) +: 8] = bytes[base_idx + i];
116+
end
117+
end
118+
119+
// Accumulate and advance
120+
out.push_back(beat);
121+
base_idx += win_len;
122+
123+
// Decide if the next beat would cross a 4 KiB boundary, exceed maximum burst length
124+
// or this is the last beat
125+
next_addr = beat_addr + win_len;
126+
crosses_4k_next = ((next_addr & 12'hFFF) == 12'h000); // next beat starts a new page
127+
exceeds_burst_length = (out.size() == SlinkBurstBeats);
128+
last_beat_in_section = (beat_addr == last_aligned);
129+
130+
if (crosses_4k_next || exceeds_burst_length || last_beat_in_section) begin
131+
// Flush accumulated beats for this page
132+
fix.vip.slink_write_beats(batch_addr, fix.vip.AxiStrbBits, out);
133+
out = {};
134+
batch_addr = next_addr;
135+
end
136+
end
137+
endtask
138+
65139
task automatic slink_32b_elf_preload(input string binary, output bit [63:0] entry);
140+
66141
longint sec_addr, sec_len;
142+
143+
// bit [32] mask;
144+
// axi_data_t rd[$];
145+
// axi_data_t wr[$] = {{'0, 32'hdeadbeef}};
146+
// $display("[SLINK] StrbBits and StrbWidth: %0d / %0d", fix.vip.AxiStrbBits, fix.vip.AxiStrbWidth);
147+
// $display("[SLINK] Testing write/read");
148+
// $display("[SLINK] Write 0xdeadbeef to 0x70002000");
149+
// fix.vip.slink_write_beats(32'h70002000, fix.vip.AxiStrbBits, wr);
150+
// fix.vip.slink_read_beats(32'h70002000, fix.vip.AxiStrbBits, 0, rd);
151+
// $display("[SLINK] Read 0x%h at 0x70002000", rd[0]);
152+
67153
$display("[SLINK] Preloading ELF binary: %s", binary);
68154
if (fix.vip.read_elf(binary)) $fatal(1, "[SLINK] Failed to load ELF!");
69-
while (fix.vip.get_section(
70-
sec_addr, sec_len
71-
)) begin
72-
byte bf [] = new[sec_len];
73-
int burst_len;
155+
156+
while (fix.vip.get_section(sec_addr, sec_len)) begin
157+
byte bf[] = new [sec_len];
74158
$display("[SLINK] Preloading section at 0x%h (%0d bytes)", sec_addr, sec_len);
75-
if (fix.vip.read_section(sec_addr, bf, sec_len))
76-
$fatal(1, "[SLINK] Failed to read ELF section!");
77-
// Write section in bursts <= SlinkBurstBytes that never cross a 4 KiB page
78-
for (longint sec_offs = 0; sec_offs < sec_len; sec_offs += burst_len) begin
79-
longint sec_left, page_left;
80-
axi_data_t beats [$];
81-
int bus_offs;
82-
addr_t addr_cur = sec_addr + sec_offs;
83-
if (sec_offs != 0) begin
84-
$display("[SLINK] - %0d/%0d bytes (%0d%%)", sec_offs, sec_len,
85-
sec_offs * 100 / (sec_len > 1 ? sec_len - 1 : 1));
86-
end
87-
// By default the burst length is SlinkBurstBytes
88-
burst_len = fix.vip.SlinkBurstBytes;
89-
// Cut the burst length if it exceeds the remaining section length
90-
// or it crosses a 4 KiB page boundary
91-
sec_left = sec_len - sec_offs;
92-
page_left = 4096 - (addr_cur & 12'hFFF);
93-
if (burst_len > sec_left) burst_len = int'(sec_left);
94-
if (burst_len > page_left) burst_len = int'(page_left);
95-
bus_offs = addr_cur[fix.vip.AxiStrbBits-1:0];
96-
97-
// If the address is not aligned subtract the offset from the burst length to avoid an additional write
98-
burst_len = burst_len - bus_offs;
99-
// Assemble beats, handling unaligned start in the first beat
100-
for (int b = -bus_offs; b < burst_len; b += fix.vip.AxiStrbWidth) begin
101-
axi_data_t beat = '0;
102-
for (int e = 0; e < fix.vip.AxiStrbWidth; ++e)
103-
if (b + e >= 0 && b + e < burst_len) beat[8*e+:8] = bf[sec_offs+b+e];
104-
beats.push_back(beat);
105-
end
106-
// Address must be beat‑aligned for slink_write_beats
107-
fix.vip.slink_write_beats(addr_cur - bus_offs, fix.vip.AxiStrbBits, beats);
108-
end
159+
if (fix.vip.read_section(sec_addr, bf, sec_len)) $fatal(1, "[SLINK] Failed to read ELF section!");
160+
slink_write_generic(sec_addr, sec_len, bf);
109161
end
162+
163+
// mask = {fix.vip.AxiStrbBits{1'b1}};
164+
// fix.vip.slink_read_beats(32'h70002df4 & ~mask, fix.vip.AxiStrbBits, 0, rd);
165+
// $display("0x%h", rd[0]);
166+
// fix.vip.slink_read_beats(32'h70002000 & ~mask, fix.vip.AxiStrbBits, 0, rd);
167+
// $display("0x%h", rd[0]);
168+
110169
void'(fix.vip.get_entry(entry));
111170
$display("[SLINK] Preload complete");
112171
endtask
113172

114-
115173
initial begin
116174
// Fetch plusargs or use safe (fail-fast) defaults
117175
if (!$value$plusargs("BOOTMODE=%d", boot_mode)) boot_mode = 0;

0 commit comments

Comments
 (0)