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