Merge pull request #18 from wallclimber21/quartus

./scripts/quartus
This commit is contained in:
Clifford Wolf 2016-08-31 17:21:23 +02:00 committed by GitHub
commit 0906b1b4b4
20 changed files with 680 additions and 0 deletions

11
scripts/quartus/.gitignore vendored Normal file
View File

@ -0,0 +1,11 @@
firmware.bin
firmware.elf
firmware.hex
firmware.map
synth_*.log
synth_*.mmi
synth_*.bit
synth_system.v
table.txt
tab_*/
system_tb

62
scripts/quartus/Makefile Normal file
View File

@ -0,0 +1,62 @@
export QUARTUS_ROOTDIR = /opt/altera_lite/16.0
export QUARTUS_BIN = $(QUARTUS_ROOTDIR)/quartus/bin
VLOG = iverilog
TOOLCHAIN_PREFIX = /opt/riscv32i/bin/riscv32-unknown-elf-
help:
@echo ""
@echo "Simple synthesis tests:"
@echo " make synth_area_{small|regular|large}"
@echo " make synth_speed"
@echo ""
@echo "Example system:"
@echo " make synth_system"
@echo " make sim_system"
@echo ""
@echo "Timing and Utilization Evaluation:"
@echo " make table.txt"
@echo " make area"
@echo ""
synth_%:
rm -f $@.log
mkdir -p $@_build
cp $@.qsf $@_build
cd $@_build && $(QUARTUS_BIN)/quartus_map $@.qsf
cd $@_build && $(QUARTUS_BIN)/quartus_fit --read_settings_files=off -write_settings_files=off $@ -c $@
cd $@_build && $(QUARTUS_BIN)/quartus_sta $@ -c $@
-cd $@_build && grep -A3 "Total logic elements" output_files/$@.fit.summary
-cd $@_build && grep -B1 "Slack" output_files/$@.sta.summary
synth_system: firmware.hex
sim_system: firmware.hex system_tb.v system.v ../../picorv32.v
$(VLOG) -o system_tb system_tb.v system.v ../../picorv32.v
./system_tb
firmware.hex: firmware.S firmware.c firmware.lds
$(TOOLCHAIN_PREFIX)gcc -Os -m32 -ffreestanding -nostdlib -o firmware.elf firmware.S firmware.c \
--std=gnu99 -Wl,-Bstatic,-T,firmware.lds,-Map,firmware.map,--strip-debug -lgcc
$(TOOLCHAIN_PREFIX)objcopy -O binary firmware.elf firmware.bin
python3 ../../firmware/makehex.py firmware.bin 4096 > firmware.hex
tab_%/results.txt:
bash tabtest.sh $@
area: synth_area_small synth_area_regular synth_area_large
-grep -A3 "Total logic elements" synth_area_*_build/output_files/synth_area_*.fit.summary
table.txt: tab_small_ep4ce_c7/results.txt
table.txt: tab_small_ep4cgx_c7/results.txt
table.txt: tab_small_5cgx_c7/results.txt
table.txt:
bash table.sh > table.txt
clean:
rm -rf firmware.bin firmware.elf firmware.hex firmware.map synth_*.log
rm -rf table.txt tab_*/
rm -rf synth_*_build

View File

@ -0,0 +1,12 @@
.section .init
.global main
/* set stack pointer */
lui sp, %hi(16*1024)
addi sp, sp, %lo(16*1024)
/* call main */
jal ra, main
/* break */
ebreak

View File

@ -0,0 +1,43 @@
void putc(char c)
{
*(volatile char*)0x10000000 = c;
}
void puts(const char *s)
{
while (*s) putc(*s++);
}
void *memcpy(void *dest, const void *src, int n)
{
while (n) {
n--;
((char*)dest)[n] = ((char*)src)[n];
}
return dest;
}
void main()
{
char message[] = "$Uryyb+Jbeyq!+Vs+lbh+pna+ernq+guvf+zrffntr+gura$gur+CvpbEI32+PCH"
"+frrzf+gb+or+jbexvat+whfg+svar.$$++++++++++++++++GRFG+CNFFRQ!$$";
for (int i = 0; message[i]; i++)
switch (message[i])
{
case 'a' ... 'm':
case 'A' ... 'M':
message[i] += 13;
break;
case 'n' ... 'z':
case 'N' ... 'Z':
message[i] -= 13;
break;
case '$':
message[i] = '\n';
break;
case '+':
message[i] = ' ';
break;
}
puts(message);
}

View File

@ -0,0 +1,11 @@
SECTIONS {
.memory : {
. = 0x000000;
*(.init);
*(.text);
*(*);
. = ALIGN(4);
end = .;
}
}

View File

@ -0,0 +1 @@
create_clock -period 20.00 [get_ports clk]

View File

@ -0,0 +1,6 @@
set_global_assignment -name DEVICE ep4ce40f29c7
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY top_large
set_global_assignment -name VERILOG_FILE ../synth_area_top.v
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE ../synth_area.sdc

View File

@ -0,0 +1,6 @@
set_global_assignment -name DEVICE ep4ce40f29c7
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY top_regular
set_global_assignment -name VERILOG_FILE ../synth_area_top.v
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE ../synth_area.sdc

View File

@ -0,0 +1,6 @@
set_global_assignment -name DEVICE ep4ce40f29c7
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY top_small
set_global_assignment -name VERILOG_FILE ../synth_area_top.v
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE ../synth_area.sdc

View File

@ -0,0 +1,140 @@
module top_small (
input clk, resetn,
output mem_valid,
output mem_instr,
input mem_ready,
output [31:0] mem_addr,
output [31:0] mem_wdata,
output [ 3:0] mem_wstrb,
input [31:0] mem_rdata
);
picorv32 #(
.ENABLE_COUNTERS(0),
.LATCHED_MEM_RDATA(1),
.TWO_STAGE_SHIFT(0),
.CATCH_MISALIGN(0),
.CATCH_ILLINSN(0)
) picorv32 (
.clk (clk ),
.resetn (resetn ),
.mem_valid(mem_valid),
.mem_instr(mem_instr),
.mem_ready(mem_ready),
.mem_addr (mem_addr ),
.mem_wdata(mem_wdata),
.mem_wstrb(mem_wstrb),
.mem_rdata(mem_rdata)
);
endmodule
module top_regular (
input clk, resetn,
output trap,
output mem_valid,
output mem_instr,
input mem_ready,
output [31:0] mem_addr,
output [31:0] mem_wdata,
output [ 3:0] mem_wstrb,
input [31:0] mem_rdata,
// Look-Ahead Interface
output mem_la_read,
output mem_la_write,
output [31:0] mem_la_addr,
output [31:0] mem_la_wdata,
output [ 3:0] mem_la_wstrb
);
picorv32 picorv32 (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.mem_la_read (mem_la_read ),
.mem_la_write(mem_la_write),
.mem_la_addr (mem_la_addr ),
.mem_la_wdata(mem_la_wdata),
.mem_la_wstrb(mem_la_wstrb)
);
endmodule
module top_large (
input clk, resetn,
output trap,
output mem_valid,
output mem_instr,
input mem_ready,
output [31:0] mem_addr,
output [31:0] mem_wdata,
output [ 3:0] mem_wstrb,
input [31:0] mem_rdata,
// Look-Ahead Interface
output mem_la_read,
output mem_la_write,
output [31:0] mem_la_addr,
output [31:0] mem_la_wdata,
output [ 3:0] mem_la_wstrb,
// Pico Co-Processor Interface (PCPI)
output pcpi_valid,
output [31:0] pcpi_insn,
output [31:0] pcpi_rs1,
output [31:0] pcpi_rs2,
input pcpi_wr,
input [31:0] pcpi_rd,
input pcpi_wait,
input pcpi_ready,
// IRQ Interface
input [31:0] irq,
output [31:0] eoi
);
picorv32 #(
.COMPRESSED_ISA(1),
.BARREL_SHIFTER(1),
.ENABLE_PCPI(1),
.ENABLE_MUL(1),
.ENABLE_IRQ(1)
) picorv32 (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.mem_la_read (mem_la_read ),
.mem_la_write (mem_la_write ),
.mem_la_addr (mem_la_addr ),
.mem_la_wdata (mem_la_wdata ),
.mem_la_wstrb (mem_la_wstrb ),
.pcpi_valid (pcpi_valid ),
.pcpi_insn (pcpi_insn ),
.pcpi_rs1 (pcpi_rs1 ),
.pcpi_rs2 (pcpi_rs2 ),
.pcpi_wr (pcpi_wr ),
.pcpi_rd (pcpi_rd ),
.pcpi_wait (pcpi_wait ),
.pcpi_ready (pcpi_ready ),
.irq (irq ),
.eoi (eoi )
);
endmodule

View File

@ -0,0 +1,5 @@
set_global_assignment -name DEVICE ep4ce40f29c7
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY picorv32_axi
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE ../synth_speed.sdc

View File

@ -0,0 +1 @@
create_clock -period 2.5 [get_ports clk]

View File

@ -0,0 +1,6 @@
set_global_assignment -name DEVICE ep4ce40f29c7
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY system
set_global_assignment -name VERILOG_FILE ../system.v
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE ../synth_system.sdc

View File

@ -0,0 +1 @@
create_clock -period 10.00 [get_ports clk]

View File

@ -0,0 +1,17 @@
read_verilog system.v
read_verilog ../../picorv32.v
read_xdc synth_system.xdc
synth_design -part xc7a35t-cpg236-1 -top system
opt_design
place_design
route_design
report_utilization
report_timing
write_verilog -force synth_system.v
write_bitstream -force synth_system.bit
# write_mem_info -force synth_system.mmi

101
scripts/quartus/system.v Normal file
View File

@ -0,0 +1,101 @@
`timescale 1 ns / 1 ps
module system (
input clk,
input resetn,
output trap,
output reg [7:0] out_byte,
output reg out_byte_en
);
// set this to 0 for better timing but less performance/MHz
parameter FAST_MEMORY = 0;
// 4096 32bit words = 16kB memory
parameter MEM_SIZE = 4096;
wire mem_valid;
wire mem_instr;
reg mem_ready;
wire [31:0] mem_addr;
wire [31:0] mem_wdata;
wire [3:0] mem_wstrb;
reg [31:0] mem_rdata;
wire mem_la_read;
wire mem_la_write;
wire [31:0] mem_la_addr;
wire [31:0] mem_la_wdata;
wire [3:0] mem_la_wstrb;
picorv32 picorv32_core (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_valid (mem_valid ),
.mem_instr (mem_instr ),
.mem_ready (mem_ready ),
.mem_addr (mem_addr ),
.mem_wdata (mem_wdata ),
.mem_wstrb (mem_wstrb ),
.mem_rdata (mem_rdata ),
.mem_la_read (mem_la_read ),
.mem_la_write(mem_la_write),
.mem_la_addr (mem_la_addr ),
.mem_la_wdata(mem_la_wdata),
.mem_la_wstrb(mem_la_wstrb)
);
reg [31:0] memory [0:MEM_SIZE-1];
initial $readmemh("firmware.hex", memory);
reg [31:0] m_read_data;
reg m_read_en;
generate if (FAST_MEMORY) begin
always @(posedge clk) begin
mem_ready <= 1;
out_byte_en <= 0;
mem_rdata <= memory[mem_la_addr >> 2];
if (mem_la_write && (mem_la_addr >> 2) < MEM_SIZE) begin
if (mem_la_wstrb[0]) memory[mem_la_addr >> 2][ 7: 0] <= mem_la_wdata[ 7: 0];
if (mem_la_wstrb[1]) memory[mem_la_addr >> 2][15: 8] <= mem_la_wdata[15: 8];
if (mem_la_wstrb[2]) memory[mem_la_addr >> 2][23:16] <= mem_la_wdata[23:16];
if (mem_la_wstrb[3]) memory[mem_la_addr >> 2][31:24] <= mem_la_wdata[31:24];
end
else
if (mem_la_write && mem_la_addr == 32'h1000_0000) begin
out_byte_en <= 1;
out_byte <= mem_la_wdata;
end
end
end else begin
always @(posedge clk) begin
m_read_en <= 0;
mem_ready <= mem_valid && !mem_ready && m_read_en;
m_read_data <= memory[mem_addr >> 2];
mem_rdata <= m_read_data;
out_byte_en <= 0;
(* parallel_case *)
case (1)
mem_valid && !mem_ready && !mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
m_read_en <= 1;
end
mem_valid && !mem_ready && |mem_wstrb && (mem_addr >> 2) < MEM_SIZE: begin
if (mem_wstrb[0]) memory[mem_addr >> 2][ 7: 0] <= mem_wdata[ 7: 0];
if (mem_wstrb[1]) memory[mem_addr >> 2][15: 8] <= mem_wdata[15: 8];
if (mem_wstrb[2]) memory[mem_addr >> 2][23:16] <= mem_wdata[23:16];
if (mem_wstrb[3]) memory[mem_addr >> 2][31:24] <= mem_wdata[31:24];
mem_ready <= 1;
end
mem_valid && !mem_ready && |mem_wstrb && mem_addr == 32'h1000_0000: begin
out_byte_en <= 1;
out_byte <= mem_wdata;
mem_ready <= 1;
end
endcase
end
end endgenerate
endmodule

View File

@ -0,0 +1,38 @@
`timescale 1 ns / 1 ps
module system_tb;
reg clk = 1;
always #5 clk = ~clk;
reg resetn = 0;
initial begin
if ($test$plusargs("vcd")) begin
$dumpfile("system.vcd");
$dumpvars(0, system_tb);
end
repeat (100) @(posedge clk);
resetn <= 1;
end
wire trap;
wire [7:0] out_byte;
wire out_byte_en;
system uut (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.out_byte (out_byte ),
.out_byte_en(out_byte_en)
);
always @(posedge clk) begin
if (resetn && out_byte_en) begin
$write("%c", out_byte);
$fflush;
end
if (resetn && trap) begin
$finish;
end
end
endmodule

17
scripts/quartus/table.sh Normal file
View File

@ -0,0 +1,17 @@
#!/bin/bash
dashes="----------------------------------------------------------------"
printf '| %-25s | %-10s | %-20s |\n' "Device" "Speedgrade" "Clock Period (Freq.)"
printf '|:%.25s |:%.10s:| %.20s:|\n' $dashes $dashes $dashes
for x in $( grep -H . tab_*/results.txt )
do
read _ size device grade _ speed < <( echo "$x" | tr _/: ' ' )
case "$device" in
ep4ce) d="Altera Cyclone IV E" ;;
ep4cgx) d="Altera Cyclone IV GX" ;;
5cgx) d="Altera Cyclone V GX" ;;
esac
speedtxt=$( printf '%s.%s ns (%d MHz)' ${speed%?} ${speed#?} $((10000 / speed)) )
printf '| %-25s | %-10s | %20s |\n' "$d" "-$grade" "$speedtxt"
done

View File

@ -0,0 +1,78 @@
#!/bin/bash
set -e
read _ ip dev grade _ < <( echo $* | tr '_/' ' '; )
# rm -rf tab_${ip}_${dev}_${grade}
mkdir -p tab_${ip}_${dev}_${grade}
cd tab_${ip}_${dev}_${grade}
max_speed=99
min_speed=01
best_speed=99
synth_case() {
if [ -f test_${1}.txt ]; then
echo "Reusing cached tab_${ip}_${dev}_${grade}/test_${1}."
return
fi
case "${dev}" in
ep4ce) al_device="ep4ce30f23${grade}" ;;
ep4cgx) al_device="ep4cgx50df27${grade}" ;;
5cgx) al_device="5cgxbc9c6f23${grade}" ;;
esac
cat > test_${1}.qsf <<- EOT
set_global_assignment -name DEVICE ${al_device}
set_global_assignment -name PROJECT_OUTPUT_DIRECTORY output_files
set_global_assignment -name TOP_LEVEL_ENTITY top
set_global_assignment -name VERILOG_FILE ../tabtest.v
set_global_assignment -name VERILOG_FILE ../../../picorv32.v
set_global_assignment -name SDC_FILE test_${1}.sdc
EOT
cat > test_${1}.sdc <<- EOT
create_clock -period ${speed%?}.${speed#?} [get_ports clk]
EOT
echo "Running tab_${ip}_${dev}_${grade}/test_${1}.."
if ! $QUARTUS_BIN/quartus_map test_${1}; then
exit 1
fi
if ! $QUARTUS_BIN/quartus_fit --read_settings_files=off --write_settings_files=off test_${1} -c test_${1}; then
exit 1
fi
if ! $QUARTUS_BIN/quartus_sta test_${1} -c test_${1}; then
exit 1
fi
cp output_files/test_${1}.sta.summary test_${1}.txt
}
countdown=7
while [ $countdown -gt 0 ]; do
speed=$(((max_speed+min_speed)/2))
synth_case $speed
if grep -q '^Slack : -' test_${speed}.txt; then
echo " tab_${ip}_${dev}_${grade}/test_${speed} VIOLATED"
min_speed=$((speed))
elif grep -q '^Slack : [^-]' test_${speed}.txt; then
echo " tab_${ip}_${dev}_${grade}/test_${speed} MET"
[ $speed -lt $best_speed ] && best_speed=$speed
max_speed=$((speed))
else
echo "ERROR: No slack line found in $PWD/test_${speed}.txt!"
exit 1
fi
countdown=$((countdown-1))
done
echo "-----------------------"
echo "Best speed for tab_${ip}_${dev}_${grade}: $best_speed"
echo "-----------------------"
echo $best_speed > results.txt

118
scripts/quartus/tabtest.v Normal file
View File

@ -0,0 +1,118 @@
module top (
input clk, io_resetn,
output io_trap,
output io_mem_axi_awvalid,
input io_mem_axi_awready,
output [31:0] io_mem_axi_awaddr,
output [ 2:0] io_mem_axi_awprot,
output io_mem_axi_wvalid,
input io_mem_axi_wready,
output [31:0] io_mem_axi_wdata,
output [ 3:0] io_mem_axi_wstrb,
input io_mem_axi_bvalid,
output io_mem_axi_bready,
output io_mem_axi_arvalid,
input io_mem_axi_arready,
output [31:0] io_mem_axi_araddr,
output [ 2:0] io_mem_axi_arprot,
input io_mem_axi_rvalid,
output io_mem_axi_rready,
input [31:0] io_mem_axi_rdata,
input [31:0] io_irq,
output [31:0] io_eoi
);
wire resetn;
wire trap;
wire mem_axi_awvalid;
wire mem_axi_awready;
wire [31:0] mem_axi_awaddr;
wire [2:0] mem_axi_awprot;
wire mem_axi_wvalid;
wire mem_axi_wready;
wire [31:0] mem_axi_wdata;
wire [3:0] mem_axi_wstrb;
wire mem_axi_bvalid;
wire mem_axi_bready;
wire mem_axi_arvalid;
wire mem_axi_arready;
wire [31:0] mem_axi_araddr;
wire [2:0] mem_axi_arprot;
wire mem_axi_rvalid;
wire mem_axi_rready;
wire [31:0] mem_axi_rdata;
wire [31:0] irq;
wire [31:0] eoi;
delay4 #( 1) delay_resetn (clk, io_resetn , resetn );
delay4 #( 1) delay_trap (clk, trap , io_trap );
delay4 #( 1) delay_mem_axi_awvalid (clk, mem_axi_awvalid, io_mem_axi_awvalid);
delay4 #( 1) delay_mem_axi_awready (clk, io_mem_axi_awready, mem_axi_awready);
delay4 #(32) delay_mem_axi_awaddr (clk, mem_axi_awaddr , io_mem_axi_awaddr );
delay4 #( 3) delay_mem_axi_awprot (clk, mem_axi_awprot , io_mem_axi_awprot );
delay4 #( 1) delay_mem_axi_wvalid (clk, mem_axi_wvalid , io_mem_axi_wvalid );
delay4 #( 1) delay_mem_axi_wready (clk, io_mem_axi_wready , mem_axi_wready );
delay4 #(32) delay_mem_axi_wdata (clk, mem_axi_wdata , io_mem_axi_wdata );
delay4 #( 4) delay_mem_axi_wstrb (clk, mem_axi_wstrb , io_mem_axi_wstrb );
delay4 #( 1) delay_mem_axi_bvalid (clk, io_mem_axi_bvalid , mem_axi_bvalid );
delay4 #( 1) delay_mem_axi_bready (clk, mem_axi_bready , io_mem_axi_bready );
delay4 #( 1) delay_mem_axi_arvalid (clk, mem_axi_arvalid, io_mem_axi_arvalid);
delay4 #( 1) delay_mem_axi_arready (clk, io_mem_axi_arready, mem_axi_arready);
delay4 #(32) delay_mem_axi_araddr (clk, mem_axi_araddr , io_mem_axi_araddr );
delay4 #( 3) delay_mem_axi_arprot (clk, mem_axi_arprot , io_mem_axi_arprot );
delay4 #( 1) delay_mem_axi_rvalid (clk, io_mem_axi_rvalid , mem_axi_rvalid );
delay4 #( 1) delay_mem_axi_rready (clk, mem_axi_rready , io_mem_axi_rready );
delay4 #(32) delay_mem_axi_rdata (clk, io_mem_axi_rdata , mem_axi_rdata );
delay4 #(32) delay_irq (clk, io_irq , irq );
delay4 #(32) delay_eoi (clk, eoi , io_eoi );
picorv32_axi #(
.TWO_CYCLE_ALU(1)
) cpu (
.clk (clk ),
.resetn (resetn ),
.trap (trap ),
.mem_axi_awvalid(mem_axi_awvalid),
.mem_axi_awready(mem_axi_awready),
.mem_axi_awaddr (mem_axi_awaddr ),
.mem_axi_awprot (mem_axi_awprot ),
.mem_axi_wvalid (mem_axi_wvalid ),
.mem_axi_wready (mem_axi_wready ),
.mem_axi_wdata (mem_axi_wdata ),
.mem_axi_wstrb (mem_axi_wstrb ),
.mem_axi_bvalid (mem_axi_bvalid ),
.mem_axi_bready (mem_axi_bready ),
.mem_axi_arvalid(mem_axi_arvalid),
.mem_axi_arready(mem_axi_arready),
.mem_axi_araddr (mem_axi_araddr ),
.mem_axi_arprot (mem_axi_arprot ),
.mem_axi_rvalid (mem_axi_rvalid ),
.mem_axi_rready (mem_axi_rready ),
.mem_axi_rdata (mem_axi_rdata ),
.irq (irq ),
.eoi (eoi )
);
endmodule
module delay4 #(
parameter WIDTH = 1
) (
input clk,
input [WIDTH-1:0] in,
output reg [WIDTH-1:0] out
);
reg [WIDTH-1:0] q1, q2, q3;
always @(posedge clk) begin
q1 <= in;
q2 <= q1;
q3 <= q2;
out <= q3;
end
endmodule