diff --git a/testbench/swcore/optimized_allocator/common.svh b/testbench/swcore/optimized_allocator/common.svh new file mode 100644 index 0000000000000000000000000000000000000000..ac91f1b988f3eda7dfad2924374167b2e03c4ead --- /dev/null +++ b/testbench/swcore/optimized_allocator/common.svh @@ -0,0 +1,289 @@ + +typedef enum + { + ALLOC, + FREE, + FORCE_FREE, + SET_USECOUNT + } alloc_req_type_t ; + +typedef struct { + alloc_req_type_t t; + int use_count; + int id, origin; + int page; + time t_event; +} alloc_request_t; + +function automatic int first_free(int tab[]); + int i; + + for(i=0;i<tab.size;i++) + if(tab[i] < 0) + return i; +endfunction // first_free + + + +function automatic int lookup_origin_page(ref alloc_request_t rqs[$], int id); + foreach(rqs[i]) + begin + if(rqs[i].id == id) + begin + // $display("Found t%d page %d\n", rqs[i].t, rqs[i].page); + + return rqs[i].page; + end + + end + $fatal("ID Not found: %i", id); +endfunction // lookup_origin_page + + +task automatic count_occupied_pages(ref alloc_request_t rqs[$], ref int peak, output int occupied, input int up_to=0, int verbose=0, int reserve_pages=1); + int i, n =0; + int page_table[1024]; /* fixme: this is ugly */ + int pages_allocated = 0; + string s = ""; + + + peak = 0; + + if(!up_to) + up_to = rqs.size() - 1; + + for(i=0;i<1024;i++) page_table[i] = -1; + // $display("----\n"); + + for(i=0;i<=up_to;i++) + begin + case(rqs[i].t) + ALLOC:begin + int page = reserve_pages?first_free(page_table) : rqs[i].page; + rqs[i].page = page; + page_table[page] = rqs[i].use_count; + pages_allocated++; + if(verbose) $display("%d : alloc %d [cnt=%d, used=%d]",i, rqs[i].page, rqs[i].use_count, pages_allocated); + + end + SET_USECOUNT: begin + int page = reserve_pages?lookup_origin_page(rqs, rqs[i].origin):rqs[i].page; + if(verbose) $display("%d : set_ucnt %d [cnt=%d]", i, page, rqs[i].use_count); + page_table[page] = rqs[i].use_count; + end + FREE: begin + int page = reserve_pages?lookup_origin_page(rqs, rqs[i].origin):rqs[i].page; + + if(page_table[page] < 0) + $fatal("attempt to free a free page\n"); + + page_table[page]--; + if(!page_table[page]) + begin + page_table[page] = -1; + pages_allocated--; + end + + if(verbose) $display("%d : free %d, used = %d", i, page, pages_allocated); + + end + + FORCE_FREE:begin + int page = reserve_pages?lookup_origin_page(rqs, rqs[i].origin):rqs[i].page; + + page_table[page] = -1; + pages_allocated--; + if(verbose) $display("%d : force_free %d, used = %d", i, page, pages_allocated); + + end + endcase // case (rqs[i].t) + + if(pages_allocated > peak) peak = pages_allocated; + + end + + + for(i=0;i<1024;i++) begin + if(page_table[i] >= 0) begin + n++; + $sformat(s, "%s %-1d", s, i); + end + end + + if(verbose) $display("Pages occupied after test: %s", s); + + occupied = n; +endtask // count_occupied_pages + + +function automatic int my_dist_uniform(ref int seed, input int start, int _end); + if(start >= _end) + return start; + + return $dist_uniform(seed, start, _end); +endfunction // my_dist_uniform + + + + +task automatic gen_random_requests(ref alloc_request_t rqs[$], input int n, int seed, int max_occupied_pages = 0, int max_use_count = 3); + int i; + static int uniq_id = 0; + int temp_page = 0; + + + for(i=0;i<=n;i++) + begin + alloc_request_t rq; + + int orig_id = uniq_id++; + int j; + int use_count = my_dist_uniform(seed, 0, max_use_count); + int orig_idx; + int idx, peak, occupied; + + idx = my_dist_uniform(seed, 0, rqs.size()-1); + + orig_idx = idx; + + // $display("Gen %d", i); + + rq.t = ALLOC; + rq.id = orig_id; + rq.use_count = use_count; + + rqs.insert(idx, rq); + + + + + if(!use_count) /* Insert a "set use count" command somewhere after the allocation request */ + begin + int idx = my_dist_uniform(seed, orig_idx + 1, rqs.size()), peak, occupied; + // $display("InsertUseCnt page=%d at=%d",temp_page-1, idx); + + rq.t = SET_USECOUNT; + rq.origin = orig_id; + rq.id = -1; + use_count = my_dist_uniform(seed, 1, max_use_count); + rq.use_count = use_count; + rqs.insert(idx, rq); + orig_idx = idx; + end + + for(j=0; j<use_count;j++) + begin + orig_idx = my_dist_uniform(seed, orig_idx + 1, rqs.size()); + rq.t = FREE; + rq.id = -1 ; + rq.origin = orig_id; + + if(my_dist_uniform(seed, 1, 100) < 20) + begin + rq.t = FORCE_FREE; + end + + // $display("Insertidx: %d size %d", idx, rqs.size()); + + rqs.insert(orig_idx, rq); + if(rq.t == FORCE_FREE) + break; + end // for (j=0; j<use_count;j++) + + temp_page++; + + end +endtask // gen_random_requests + + +interface IAllocatorPort (input clk_i); + + // make sure they are the same as in the main one + parameter g_page_addr_width= 10; + parameter g_usecnt_width = 5; + + logic alloc=0, free=0, force_free=0, set_usecnt=0, done; + logic alloc_done, free_done, force_free_done, set_usecnt_done; + logic free_last_usecnt; + logic no_mem; + + + logic [g_page_addr_width-1:0] pg_addr_free; + logic [g_page_addr_width-1:0] pg_addr_force_free; + logic [g_page_addr_width-1:0] pg_addr_usecnt; + logic [g_page_addr_width-1:0] pg_addr_alloc, pg_addr_muxed; + logic [g_usecnt_width-1:0] usecnt; + + assign pg_addr_muxed = free ? pg_addr_free : + force_free ? pg_addr_force_free : + pg_addr_usecnt; + +endinterface // IAllocatorPort + +// `ifdef dupa1234 +typedef virtual IAllocatorPort VIAllocatorPort; + +task automatic execute_requests(VIAllocatorPort port, ref alloc_request_t rqs[$], input int verbose =0); + + int i,j=0, idx; + for(idx=0;idx<rqs.size();idx++) + begin +// if(port.no_mem) begin +// while(rqs[idx+j].t == ALLOC && idx+j < rqs.size()) +// j++; +// while(rqs[idx+j].origin > rqs[idx].id && idx+j < rqs.size()) +// j++; +// end +// i = idx+j; + i = idx; +// $display("Request id=%d", i); + case(rqs[i].t) + ALLOC: begin + port.alloc <= 1; + port.usecnt <= rqs[i].use_count; + + @(posedge port.clk_i); + while(!port.done) @(posedge port.clk_i); + port.alloc <= 0; + rqs[i].page = port.pg_addr_alloc; + if(verbose)$display("Alloc [id=%-1d, usecount=%-1d, page=%-1d]", rqs[i].id, rqs[i].use_count, rqs[i].page); + end + + SET_USECOUNT:begin + rqs[i].page = lookup_origin_page(rqs, rqs[i].origin); + if(verbose) $display("Set_Usecount [origin=%-1d, usecount=%-1d, page=%-1d]", rqs[i].origin, rqs[i].use_count, rqs[i].page); + port.pg_addr_usecnt <= rqs[i].page; + port.usecnt <= rqs[i].use_count; + port.set_usecnt <= 1; + @(posedge port.clk_i); + while(!port.done) @(posedge port.clk_i); + port.set_usecnt <= 0; + end + + FREE: begin + rqs[i].page = lookup_origin_page(rqs, rqs[i].origin); + if(verbose)$display("Free [origin=%-1d, page=%-1d]", rqs[i].origin, rqs[i].page); + port.pg_addr_free <= rqs[i].page; + port.free <= 1; + @(posedge port.clk_i); + while(!port.done) @(posedge port.clk_i); + port.free <= 0; +// if(idx != i) rqs.delete(i); //delete executed command (so that we don't repeat later) + end + + FORCE_FREE: begin + rqs[i].page = lookup_origin_page(rqs, rqs[i].origin); + if(verbose)$display("Forced Free [origin=%-1d, page=%-1d]", rqs[i].origin, rqs[i].page); + port.pg_addr_force_free <= rqs[i].page; + port.force_free <= 1; + @(posedge port.clk_i); + while(!port.done) @(posedge port.clk_i); + port.force_free <= 0; +// if(idx != i) rqs.delete(i); //delete executed command (so that we don't repeat later) + end + + endcase // case (rqs[i].t) +// @(posedge port.clk_i); + end + endtask // execute_requests +// `endif \ No newline at end of file diff --git a/testbench/swcore/optimized_allocator/multiport.sv b/testbench/swcore/optimized_allocator/multiport.sv new file mode 100644 index 0000000000000000000000000000000000000000..bcbe6f47ebf02a5f22e8efd58dacd70efc479888 --- /dev/null +++ b/testbench/swcore/optimized_allocator/multiport.sv @@ -0,0 +1,155 @@ +`timescale 1ns/1ns + +`include "common.svh" + +module main; + + // make sure they are the same as in the interface + `define c_num_ports 7 + `define c_page_addr_width 10 + `define c_use_count_width 5 + + reg clk = 0; + reg rst_n = 0; + int page_cnt = 0; + + IAllocatorPort + #( + .g_page_addr_width (`c_page_addr_width), + .g_usecnt_width (`c_use_count_width)) alloc_port[`c_num_ports] (clk) ; + VIAllocatorPort valloc_port[`c_num_ports] = alloc_port; + + + genvar i; + + wire [`c_num_ports-1:0] alloc_v, free_v, force_free_v, set_usecnt_v; + wire [`c_num_ports-1:0] alloc_done_v, free_done_v, force_free_done_v, set_usecnt_done_v; + wire [`c_num_ports * `c_page_addr_width - 1 : 0] pgaddr_free_v, pgaddr_force_free_v, pgaddr_usecnt_v; + wire [`c_num_ports * `c_use_count_width - 1 : 0] usecnt_v; + wire [`c_page_addr_width-1:0] pg_addr_alloc; + wire pg_nomem; + + + generate + for(i=0;i<`c_num_ports;i++) + begin + + assign alloc_v[i] = alloc_port[i].alloc; + assign free_v[i] = alloc_port[i].free; + assign force_free_v[i] = alloc_port[i].force_free; + assign set_usecnt_v[i] = alloc_port[i].set_usecnt; + assign alloc_port[i].done = (alloc_done_v[i] | free_done_v[i] | force_free_done_v[i] | set_usecnt_done_v[i]); + assign alloc_port[i].pg_addr_alloc = pg_addr_alloc; + assign alloc_port[i].no_mem = pg_nomem; + assign pgaddr_free_v[(i+1) * `c_page_addr_width - 1: i * `c_page_addr_width] = alloc_port[i].pg_addr_free; + assign pgaddr_force_free_v[(i+1) * `c_page_addr_width - 1: i * `c_page_addr_width] = alloc_port[i].pg_addr_force_free; + assign pgaddr_usecnt_v[(i+1) * `c_page_addr_width - 1: i * `c_page_addr_width] = alloc_port[i].pg_addr_usecnt; + assign usecnt_v[(i+1) * `c_use_count_width - 1 : i * `c_use_count_width]=alloc_port[i].usecnt; + end + + endgenerate + + + + + swc_multiport_page_allocator + #( + .g_page_num (1024), + .g_page_addr_width (`c_page_addr_width), + .g_num_ports (`c_num_ports), + .g_usecount_width (`c_use_count_width) + ) DUT ( + .clk_i (clk), + .rst_n_i (rst_n), + + .alloc_i (alloc_v), + .free_i(free_v), + .force_free_i(force_free_v), + .set_usecnt_i(set_usecnt_v), + + .alloc_done_o(alloc_done_v), + .free_done_o(free_done_v), + .force_free_done_o(force_free_done_v), + .set_usecnt_done_o(set_usecnt_done_v), + + .pgaddr_free_i(pgaddr_free_v), + .pgaddr_force_free_i(pgaddr_force_free_v), + .pgaddr_usecnt_i(pgaddr_usecnt_v), + .usecnt_i(usecnt_v), + + .pgaddr_alloc_o(pg_addr_alloc), + .nomem_o(pg_nomem) + ); + + const int MAX_USE_COUNT=3; + int uniq_id = 0; + + + + always #8ns clk <= ~clk; + initial begin + repeat(3) @(posedge clk); + rst_n = 1; + end + + task automatic test_port(VIAllocatorPort port, int initial_seed, int n_seeds, int n_requests); + + alloc_request_t rqs[$]; + int seed; + + for(seed = initial_seed; seed < initial_seed + n_seeds; seed++) + begin + automatic int init_seed = seed; + int occupied, peak; + + rqs = '{}; + gen_random_requests(rqs, n_requests, init_seed, 100 /*max_page_occ*/, 17 /*usecnt*/); + count_occupied_pages(rqs, peak, occupied, rqs.size()-1); + $display("Peak Page Usage: %d\n", peak); + + execute_requests(port, rqs, 0); + end + endtask // test_port + + initial begin + int port_idx; + + while(!rst_n) @(posedge clk); + repeat(3000) @(posedge clk);// initializign + + for(port_idx=0;port_idx < `c_num_ports; port_idx++) + fork + automatic int k_idx = port_idx; + test_port(valloc_port[k_idx], k_idx * 100 /*initial seed*/, 10/*100 n_seed*/, 200/*200 requets*/); + join_none + + repeat(100000) @(posedge clk); + + $display("free_blocks = %-1d vs. page_cnt = %-1d", DUT.ALLOC_CORE.free_pages, page_cnt); + if(DUT.ALLOC_CORE.free_blocks != 1023) + $fatal("Pages missing"); + + end // initial begin + + + initial begin + + while(!rst_n) @(posedge clk); + + page_cnt = DUT.ALLOC_CORE.free_pages; + + forever begin + if(DUT.ALLOC_CORE.alloc_req_d1.alloc) + page_cnt = page_cnt-1; + else if(DUT.ALLOC_CORE.alloc_req_d1.f_free) + page_cnt=page_cnt+1; + else if(DUT.pg_free_last_usecnt) + page_cnt=page_cnt+1; + @(posedge clk); +// $display("free_blocks = %-1d vs. page_cnt = %-1d", DUT.ALLOC_CORE.free_pages, page_cnt); + end + + + end // initial begin + +endmodule // main diff --git a/testbench/swcore/optimized_allocator/run-multiport.do b/testbench/swcore/optimized_allocator/run-multiport.do new file mode 100644 index 0000000000000000000000000000000000000000..2891c4e52a857af28b1475ec764422c0dd319653 --- /dev/null +++ b/testbench/swcore/optimized_allocator/run-multiport.do @@ -0,0 +1,12 @@ +make -f Makefile +vlog +incdir+../../sim +incdir+../../ip_cores/wr-cores/sim multiport.sv + +vsim -L secureip -L unisim -t 10fs work.main -voptargs="+acc" +nowarn8684 +nowarn8683 + +set StdArithNoWarnings 1 +set NumericStdNoWarnings 1 +do wave-multiport.do +radix -hexadecimal +run 60us +wave zoomfull +radix -hexadecimal \ No newline at end of file diff --git a/testbench/swcore/optimized_allocator/run.do b/testbench/swcore/optimized_allocator/run.do new file mode 100644 index 0000000000000000000000000000000000000000..9d92fea8d0c9e12e6b7e238aed8699d4b4d3efce --- /dev/null +++ b/testbench/swcore/optimized_allocator/run.do @@ -0,0 +1,12 @@ +make -f Makefile +vlog +incdir+../../sim +incdir+../../ip_cores/wr-cores/sim main.sv + +vsim -L secureip -L unisim -t 10fs work.main -voptargs="+acc" +nowarn8684 +nowarn8683 + +set StdArithNoWarnings 1 +set NumericStdNoWarnings 1 +do wave.do +radix -hexadecimal +run 1000us +wave zoomfull +radix -hexadecimal \ No newline at end of file