Add multiplier test
diff --git a/.github/workflows/microwatt_ci.yml b/.github/workflows/microwatt_ci.yml index ca15150..6807cd1 100644 --- a/.github/workflows/microwatt_ci.yml +++ b/.github/workflows/microwatt_ci.yml
@@ -63,6 +63,7 @@ "minimal", "uart", "memory_test", + "multiplier", "spi_flash", "simplebus_minimal", #"simplebus_micropython",
diff --git a/verilog/dv/microwatt/multiply/Makefile b/verilog/dv/microwatt/multiply/Makefile new file mode 100644 index 0000000..3699c6d --- /dev/null +++ b/verilog/dv/microwatt/multiply/Makefile
@@ -0,0 +1,25 @@ +# SPDX-FileCopyrightText: 2020 Efabless Corporation +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# SPDX-License-Identifier: Apache-2.0 + +include ../make.env + +PATTERN = multiply +all: ${PATTERN:=.vcd} + +microwatt.elf: microwatt.c ../lib/console.c ../lib/head.S ../microwatt.lds + $(POWERPC_CROSS_COMPILE)gcc $(POWERPC_CFLAGS) -Wl,-T,../microwatt.lds -o $@ microwatt.c ../lib/console.c ../lib/head.S + +include ../make.rules
diff --git a/verilog/dv/microwatt/multiply/microwatt.c b/verilog/dv/microwatt/multiply/microwatt.c new file mode 100644 index 0000000..17bd6ea --- /dev/null +++ b/verilog/dv/microwatt/multiply/microwatt.c
@@ -0,0 +1,141 @@ +#include <stdint.h> + +#include "microwatt_util.h" +#include "console.h" + +static inline uint64_t ppc_mulld(uint64_t a, uint64_t b) +{ + uint64_t res; + __asm__ ("mulld %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline uint64_t ppc_mulhdu(uint64_t a, uint64_t b) +{ + uint64_t res; + __asm__ ("mulhdu %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline int64_t ppc_mulhd(int64_t a, int64_t b) +{ + int64_t res; + __asm__ ("mulhd %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline uint32_t ppc_mullw(uint32_t a, uint32_t b) +{ + uint32_t res; + __asm__ ("mullw %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline uint32_t ppc_mulhwu(uint32_t a, uint32_t b) +{ + uint32_t res; + __asm__ ("mulhwu %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline int32_t ppc_mulhw(int32_t a, int32_t b) +{ + int32_t res; + __asm__ ("mulhw %0,%1,%2" : "=r"(res) : "r"(a), "r"(b)); + + return res; +} + +static inline uint64_t ppc_maddld(uint64_t a, uint64_t b, uint64_t c) +{ + uint64_t res; + __asm__ ("maddld %0,%1,%2,%3" : "=r"(res) : "r"(a), "r"(b), "r"(c)); + + return res; +} + +static inline uint64_t ppc_maddhdu(uint64_t a, uint64_t b, uint64_t c) +{ + uint64_t res; + __asm__ ("maddhdu %0,%1,%2,%3" : "=r"(res) : "r"(a), "r"(b), "r"(c)); + + return res; +} + +static inline uint64_t ppc_maddhd(int64_t a, int64_t b, int64_t c) +{ + int64_t res; + __asm__ ("maddhd %0,%1,%2,%3" : "=r"(res) : "r"(a), "r"(b), "r"(c)); + + return res; +} + +static void print_hex(unsigned long val) +{ + int i, x; + + for (i = 60; i >= 0; i -= 4) { + x = (val >> i) & 0xf; + if (x >= 10) + putchar(x + 'a' - 10); + else + putchar(x + '0'); + } +} + +static void expect(char *insn, uint64_t got, uint64_t exp) +{ + if (exp != got) { + print_hex(exp); + putchar(' '); + print_hex(got); + + microwatt_failure(); + + while (1) + /* Do Nothing */ ; + } +} + +#define SIGNED_A -1245234234L +#define SIGNED_B 5434564742966924118UL +#define SIGNED_C -5551512323435643331L + +#define UNSIGNED_A 89471432132552525UL +#define UNSIGNED_B 5434564742966924118UL +#define UNSIGNED_C 17184923449516151310UL + +#define SIGNED_A_32 -1245234234L +#define SIGNED_B_32 543456474U + +#define UNSIGNED_A_32 894714321U +#define UNSIGNED_B_32 543456474U + +int main(void) +{ + console_init(); + microwatt_alive(); + + expect("mulld", ppc_mulld(UNSIGNED_A, UNSIGNED_B), 0x2806d04a5b762ade); + expect("muldhu", ppc_mulhdu(UNSIGNED_A, UNSIGNED_B), 0x5da5660c80b36e); + expect("mulhd", ppc_mulhd(SIGNED_A, SIGNED_B), 0xffffffffea223733); + + expect("maddld", ppc_maddld(UNSIGNED_A, UNSIGNED_B, UNSIGNED_C), 0x1683ed1e4026fcec); + expect("maddhdu", ppc_maddhdu(UNSIGNED_A, UNSIGNED_B, UNSIGNED_C), 0x5da5660c80b36f); + expect("maddhd", ppc_maddhd(SIGNED_A, SIGNED_B, SIGNED_C), 0xffffffffea223732); + + // Test 32 bit multiplies + expect("mullw", ppc_mullw(UNSIGNED_A_32, UNSIGNED_B_32), 0xf4547fa); + expect("mulhwu", ppc_mulhwu(UNSIGNED_A_32, UNSIGNED_B_32), 0x6bf7726); + expect("mulhw", ppc_mulhw(SIGNED_A_32, SIGNED_B_32), 0xfffffffff69bc519); + + microwatt_success(); + + while (1) + /* Do Nothing */ ; +}
diff --git a/verilog/dv/microwatt/multiply/multiply_tb.v b/verilog/dv/microwatt/multiply/multiply_tb.v new file mode 100644 index 0000000..2e72a5a --- /dev/null +++ b/verilog/dv/microwatt/multiply/multiply_tb.v
@@ -0,0 +1,167 @@ +`default_nettype none +/* + * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at> + * Copyright (C) 2018 Tim Edwards <tim@efabless.com> + * Copyright (C) 2020 Anton Blanchard <anton@linux.ibm.com> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +`timescale 1 ns / 1 ps + +`include "uprj_netlists.v" +`include "caravel_netlists.v" +`include "spiflash.v" +`include "tbuart_modified.v" + +module multiply_test; + reg clock; + reg RSTB; + reg microwatt_reset; + reg power1, power2; + reg power3, power4; + + wire gpio; + wire [37:0] mprj_io; + wire [15:0] checkbits; + wire user_flash_csb; + wire user_flash_clk; + inout user_flash_io0; + inout user_flash_io1; + wire uart_tx; + + assign mprj_io[7] = microwatt_reset; + + assign mprj_io[35] = 1'b1; // Boot from flash + // + assign user_flash_csb = mprj_io[8]; + assign user_flash_clk = mprj_io[9]; + assign user_flash_io0 = mprj_io[10]; + assign mprj_io[11] = user_flash_io1; + + assign checkbits = mprj_io[31:16]; + + assign uart_tx = mprj_io[6]; + assign mprj_io[5] = 1'b1; + + assign mprj_io[3] = 1'b1; // Force CSB high. + + // 100 MHz clock + always #5 clock <= (clock === 1'b0); + + initial begin + clock = 0; + end + + initial begin + //$dumpfile("multiply_test.vcd"); + //$dumpvars(0, multiply_test); + + $display("Microwatt multiply test"); + + repeat (500000) @(posedge clock); + $display("Timeout"); + $finish; + end + + initial begin + RSTB <= 1'b0; + microwatt_reset <= 1'b1; + #1000; + microwatt_reset <= 1'b0; + // Note: keep management engine in reset + //RSTB <= 1'b1; + end + + initial begin // Power-up sequence + power1 <= 1'b0; + power2 <= 1'b0; + power3 <= 1'b0; + power4 <= 1'b0; + #100; + power1 <= 1'b1; + #100; + power2 <= 1'b1; + #100; + power3 <= 1'b1; + #100; + power4 <= 1'b1; + end + + always @(checkbits) begin + wait(checkbits == 16'h0ffe) + $display("Microwatt alive!"); + + wait(checkbits != 16'h0ffe); + + if(checkbits == 16'h7345) begin + $display("Fail"); + $finish; + end + + if(checkbits == 16'h00d5) begin + $display("Success"); + $finish; + end + + $display("Unknown Failure %x", checkbits); + $finish; + end + + wire VDD3V3 = power1; + wire VDD1V8 = power2; + wire USER_VDD3V3 = power3; + wire USER_VDD1V8 = power4; + wire VSS = 1'b0; + + caravel uut ( + .vddio (VDD3V3), + .vssio (VSS), + .vdda (VDD3V3), + .vssa (VSS), + .vccd (VDD1V8), + .vssd (VSS), + .vdda1 (USER_VDD3V3), + .vdda2 (USER_VDD3V3), + .vssa1 (VSS), + .vssa2 (VSS), + .vccd1 (USER_VDD1V8), + .vccd2 (USER_VDD1V8), + .vssd1 (VSS), + .vssd2 (VSS), + .clock (clock), + .gpio (gpio), + .mprj_io (mprj_io), + .resetb (RSTB) + ); + + spiflash #( + .FILENAME("microwatt.hex") + ) spiflash_microwatt ( + .csb(user_flash_csb), + .clk(user_flash_clk), + .io0(user_flash_io0), + .io1(user_flash_io1), + .io2(), // not used + .io3() // not used + ); + + tbuart_modified #( + .baud_rate(115200) + ) tbuart ( + .ser_rx(uart_tx) + ); + +endmodule +`default_nettype wire
diff --git a/verilog/dv/microwatt/multiply/tbuart_modified.v b/verilog/dv/microwatt/multiply/tbuart_modified.v new file mode 100644 index 0000000..ad9b8f9 --- /dev/null +++ b/verilog/dv/microwatt/multiply/tbuart_modified.v
@@ -0,0 +1,83 @@ +`default_nettype none +/* + * PicoSoC - A simple example SoC using PicoRV32 + * + * Copyright (C) 2017 Clifford Wolf <clifford@clifford.at> + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + */ + +`timescale 1 ns / 1 ps + +/* tbuart --- mimic an external UART display, operating at 9600 baud */ +/* and accepting ASCII characters for display. */ + +/* To do: Match a known UART 3.3V 16x2 LCD display. However, it */ +/* should be possible on a testing system to interface to the UART */ +/* pins on a Raspberry Pi, also running at 3.3V. */ + +module tbuart_modified # ( + parameter baud_rate = 115200 +) ( + input ser_rx +); + reg [3:0] recv_state; + reg [2:0] recv_divcnt; + reg [7:0] recv_pattern; + + reg clk; + + initial begin + clk <= 1'b0; + recv_state <= 0; + recv_divcnt <= 0; + recv_pattern <= 0; + end + + // Our simulation is in nanosecond steps and we want 5 clocks per bit, + // ie 10 clock transitions + always #(1000000000/baud_rate/10) clk <= (clk === 1'b0); + + always @(posedge clk) begin + recv_divcnt <= recv_divcnt + 1; + case (recv_state) + 0: begin + if (!ser_rx) + recv_state <= 1; + recv_divcnt <= 0; + end + 1: begin + if (2*recv_divcnt > 3'd3) begin + recv_state <= 2; + recv_divcnt <= 0; + end + end + 10: begin + if (recv_divcnt > 3'd3) begin + recv_state <= 0; + $write("%c", recv_pattern); + $fflush(); + end + end + default: begin + if (recv_divcnt > 3'd3) begin + recv_pattern <= {ser_rx, recv_pattern[7:1]}; + recv_state <= recv_state + 1; + recv_divcnt <= 0; + end + end + endcase + end + +endmodule