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