Răsfoiți Sursa

Added fixed-point signed divider to MU. Integrated into FPCALC.

bart 1 an în urmă
părinte
comite
f3f3a43044

+ 13 - 0
BCC/userBDOS/FPCALC.C

@@ -23,6 +23,8 @@ fixed_point_t CALC_b = 0;
 
 char CALC_state = CALC_STATE_INPUTSTART;
 
+
+
 word calcLoop()
 {
   if (CALC_state == CALC_STATE_INPUTSTART)
@@ -71,6 +73,17 @@ word calcLoop()
         BDOS_PrintConsole("\n\nInput A:      ");
       }
 
+      else if (c == '/')
+      {
+        BDOS_PrintlnConsole("/");
+        char buffer[24];
+        FP_FPtoString(FP_Div(CALC_a, CALC_b), buffer, 5);
+        BDOS_PrintConsole("Result =      ");
+        BDOS_PrintlnConsole(buffer);
+        CALC_state = CALC_STATE_INPUTA;
+        BDOS_PrintConsole("\n\nInput A:      ");
+      }
+
       else if (c == 0x1b) // escape
       {
         BDOS_PrintcConsole('\n');

+ 16 - 0
BCC/userBDOS/LIB/FP.C

@@ -165,3 +165,19 @@ fixed_point_t FP_Mult(fixed_point_t a, fixed_point_t b)
 
   return retval;
 }
+
+// Divide two fixed-point numbers using MU (a/b)
+fixed_point_t FP_Div(fixed_point_t a, fixed_point_t b)
+{
+  // r4: a, r5: b
+  fixed_point_t retval = 0;
+  asm(
+    "load32 0xC02742 r2 ; r2 = addr div_writea\n"
+    "write 0 r2 r4 ; write a to divider\n"
+    "write 1 r2 r5 ; write b to divider and perform division\n"
+    "read 1 r2 r2  ; read result to r2\n"
+    "write -4 r14 r2  ; write result to stack for return\n"
+    );
+
+  return retval;
+}

+ 4 - 3
Quartus/FPGC.qsf

@@ -224,8 +224,12 @@ set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to GPI[1]
 set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to GPI[2]
 set_instance_assignment -name WEAK_PULL_UP_RESISTOR ON -to GPI[3]
 set_global_assignment -name OPTIMIZATION_MODE "HIGH PERFORMANCE EFFORT"
+set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON
+set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
+set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW
 set_global_assignment -name SDC_FILE FPGC.sdc
 set_global_assignment -name VERILOG_FILE modules/FPGC.v
+set_global_assignment -name VERILOG_FILE modules/IO/Divider.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L1Icache.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L1Dcache.v
 set_global_assignment -name VERILOG_FILE modules/Memory/L2cache.v
@@ -267,7 +271,4 @@ set_global_assignment -name VERILOG_FILE modules/DtrReset.v
 set_global_assignment -name QIP_FILE ddr.qip
 set_global_assignment -name QIP_FILE mainpll.qip
 set_global_assignment -name SIP_FILE mainpll.sip
-set_global_assignment -name TIMING_ANALYZER_MULTICORNER_ANALYSIS ON
-set_global_assignment -name NUM_PARALLEL_PROCESSORS ALL
-set_global_assignment -name ALM_REGISTER_PACKING_EFFORT LOW
 set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top

BIN
Quartus/FPGC.qws


+ 172 - 0
Quartus/modules/IO/Divider.v

@@ -0,0 +1,172 @@
+/*
+* 32-bit multicycle divider
+*/
+
+/*
+module Divider(
+    input clk,
+    input reset,
+    input start,
+    input [31:0] data,
+
+    output done,
+    output [31:0] q
+);
+*/
+
+module Divider #(
+    parameter WIDTH=32,  // width of numbers in bits (integer and fractional)
+    parameter FBITS=16   // fractional bits within WIDTH
+    ) (
+    input clk,    // clock
+    input rst,    // reset
+    input start,  // start calculation
+    input write_a,
+    output reg busy = 1'b0,   // calculation in progress
+    output  reg    done = 1'b0,   // calculation is complete (high for one tick)
+    output   reg   valid = 1'b0,  // result is valid
+    output   reg   dbz = 1'b0,    // divide by zero
+    output   reg   ovf = 1'b0,    // overflow
+    input signed [WIDTH-1:0] a_in,   // dividend (numerator)
+    input signed [WIDTH-1:0] b,   // divisor (denominator)
+    output reg signed [WIDTH-1:0] val = 32'd0 // result value: quotient
+    );
+
+
+    reg signed [WIDTH-1:0] a = 0;
+
+    always @(posedge clk)
+    begin
+        if (write_a)
+        begin
+            a <= a_in;
+        end
+        
+    end
+
+    localparam WIDTHU = WIDTH - 1;                 // unsigned widths are 1 bit narrower
+    localparam FBITSW = (FBITS == 0) ? 1 : FBITS;  // avoid negative vector width when FBITS=0
+    localparam SMALLEST = {1'b1, {WIDTHU{1'b0}}};  // smallest negative number
+
+    localparam ITER = WIDTHU + FBITS;  // iteration count: unsigned input width + fractional bits
+    reg [$clog2(ITER):0] i;          // iteration counter (allow ITER+1 iterations for rounding)
+
+    reg a_sig = 1'b0;
+    reg b_sig = 1'b0;
+    reg sig_diff = 1'b0;      // signs of inputs and whether different
+
+    reg [WIDTHU-1:0] au = 0;
+    reg [WIDTHU-1:0] bu = 0;         // absolute version of inputs (unsigned)
+
+    reg [WIDTHU-1:0] quo = 0;
+    reg [WIDTHU-1:0] quo_next = 0;  // intermediate quotients (unsigned)
+
+    reg [WIDTHU:0] acc = 0;
+    reg [WIDTHU:0] acc_next = 0;    // accumulator (unsigned but 1 bit wider)
+
+    // input signs
+    always @(*)
+    begin
+        a_sig = a[WIDTH-1+:1];
+        b_sig = b[WIDTH-1+:1];
+    end
+
+    // division algorithm iteration
+    always @(*)
+    begin
+        if (acc >= {1'b0, bu}) begin
+            acc_next = acc - bu;
+            {acc_next, quo_next} = {acc_next[WIDTHU-1:0], quo, 1'b1};
+        end else begin
+            {acc_next, quo_next} = {acc, quo} << 1;
+        end
+    end
+
+    // calculation state machine
+    parameter IDLE    = 5'd0;
+    parameter INIT    = 5'd1;
+    parameter CALC    = 5'd2;
+    parameter ROUND   = 5'd3;
+    parameter SIGN    = 5'd4;
+    parameter DONE    = 5'd5;
+
+    reg [2:0] state = IDLE;
+
+    always @(posedge clk) begin
+        done <= 0;
+        case (state)
+            INIT: begin
+                state <= CALC;
+                ovf <= 0;
+                i <= 0;
+                {acc, quo} <= {{WIDTHU{1'b0}}, au, 1'b0};  // initialize calculation
+            end
+            CALC: begin
+                if (i == WIDTHU-1 && quo_next[WIDTHU-1:WIDTHU-FBITSW] != 0) begin  // overflow
+                    state <= DONE;
+                    busy <= 0;
+                    done <= 1;
+                    ovf <= 1;
+                end else begin
+                    if (i == ITER-1) state <= ROUND;  // calculation complete after next iteration
+                    i <= i + 1;
+                    acc <= acc_next;
+                    quo <= quo_next;
+                end
+            end
+            ROUND: begin  // Gaussian rounding
+                state <= SIGN;
+                if (quo_next[0] == 1'b1) begin  // next digit is 1, so consider rounding
+                    // round up if quotient is odd or remainder is non-zero
+                    if (quo[0] == 1'b1 || acc_next[WIDTHU:1] != 0) quo <= quo + 1;
+                end
+            end
+            SIGN: begin  // adjust quotient sign if non-zero and input signs differ
+                state <= DONE;
+                if (quo != 0) val <= (sig_diff) ? {1'b1, -quo} : {1'b0, quo};
+                busy <= 0;
+                done <= 1;
+                valid <= 1;
+            end
+            DONE: begin
+                done <= 1;
+                state <= IDLE;
+            end
+            default: begin  // IDLE
+                if (start) begin
+                    valid <= 0;
+                    if (b == 0) begin  // divide by zero
+                        state <= DONE;
+                        busy <= 0;
+                        done <= 1;
+                        dbz <= 1;
+                        ovf <= 0;
+                    end else if (a == SMALLEST || b == SMALLEST) begin  // overflow
+                        state <= DONE;
+                        busy <= 0;
+                        done <= 1;
+                        dbz <= 0;
+                        ovf <= 1;
+                    end else begin
+                        state <= INIT;
+                        au <= (a_sig) ? -a[WIDTHU-1:0] : a[WIDTHU-1:0];  // register abs(a)
+                        bu <= (b_sig) ? -b[WIDTHU-1:0] : b[WIDTHU-1:0];  // register abs(b)
+                        sig_diff <= (a_sig ^ b_sig);  // register input sign difference
+                        busy <= 1;
+                        dbz <= 0;
+                        ovf <= 0;
+                    end
+                end
+            end
+        endcase
+        if (rst) begin
+            state <= IDLE;
+            busy <= 0;
+            done <= 0;
+            valid <= 0;
+            dbz <= 0;
+            ovf <= 0;
+            val <= 0;
+        end
+    end
+endmodule

+ 39 - 2
Quartus/modules/Memory/MemoryUnit.v

@@ -160,7 +160,9 @@ localparam
     //A_SNESPAD = 35,
     A_PS2 = 36,
     A_BOOTMODE = 37,
-    A_VRAMPX = 38;
+    A_VRAMPX = 38,
+    A_DIVWA = 39,
+    A_DIVSTART = 40;
 
 //------------
 //SPI0 (flash) TODO: move this to a separate module
@@ -525,6 +527,29 @@ Keyboard PS2Keyboard (
 );
 
 
+wire [31:0] div_input;
+wire div_write_a;
+wire div_busy;
+
+wire [31:0] div_val;
+
+
+Divider divider(
+.clk        (clk), 
+.rst        (reset),
+.start      (div_start),  // start calculation
+.write_a    (div_write_a),
+.busy       (div_busy),   // calculation in progress
+//.done       (div_done),   // calculation is complete (high for one tick)
+//.valid      (valid),  // result is valid
+//.dbz        (dbz),    // divide by zero
+//.ovf        (ovf),    // overflow
+.a_in       (bus_data),   // dividend (numerator)
+.b          (bus_data),   // divisor (denominator)
+.val        (div_val)  // result value: quotient
+);
+
+
 reg [31:0] bus_d_reg = 32'd0;
 
 //----
@@ -606,6 +631,9 @@ assign OST3_trigger     = (bus_addr == 27'hC0273E && bus_we);
 //SNES
 //assign SNES_start       = bus_addr == 27'hC0273F && bus_start;
 
+//Divider
+assign div_write_a      = (bus_addr == 27'hC02742 && bus_we);
+assign div_start        = (bus_addr == 27'hC02743 && bus_we);
 
 
 reg [5:0] a_sel;
@@ -652,6 +680,8 @@ begin
     //if (bus_addr == 27'hC0273F) a_sel = A_SNESPAD;
     if (bus_addr == 27'hC02740) a_sel = A_PS2;
     if (bus_addr == 27'hC02741) a_sel = A_BOOTMODE;
+    if (bus_addr == 27'hC02742) a_sel = A_DIVWA;
+    if (bus_addr == 27'hC02743) a_sel = A_DIVSTART;
     if (bus_addr >= 27'hD00000 && bus_addr < 27'hD12C00) a_sel = A_VRAMPX;
 end
 
@@ -698,7 +728,8 @@ begin
         //A_SNESPAD:      bus_q_wire = {16'd0, SNES_state};
         A_PS2:          bus_q_wire = {24'd0, PS2_scanCode};
         A_BOOTMODE:     bus_q_wire = {31'd0, boot_mode};
-        A_VRAMPX:      bus_q_wire = VRAMpx_cpu_q;
+        A_VRAMPX:       bus_q_wire = VRAMpx_cpu_q;
+        A_DIVSTART:     bus_q_wire = div_val;
         default:        bus_q_wire = 32'd0;
     endcase
 end
@@ -902,6 +933,12 @@ begin
                     bus_done <= 1'b1;
                 end
 
+                A_DIVSTART:
+                begin
+                    if (!div_busy)
+                        if (!bus_done_next) bus_done_next <= 1'b1;
+                end
+
                 default:
                 begin
                     if (!bus_done_next) bus_done_next <= 1'b1;

BIN
Quartus/output_files/output_file.jic


+ 172 - 0
Verilog/modules/IO/Divider.v

@@ -0,0 +1,172 @@
+/*
+* 32-bit multicycle divider
+*/
+
+/*
+module Divider(
+    input clk,
+    input reset,
+    input start,
+    input [31:0] data,
+
+    output done,
+    output [31:0] q
+);
+*/
+
+module Divider #(
+    parameter WIDTH=32,  // width of numbers in bits (integer and fractional)
+    parameter FBITS=16   // fractional bits within WIDTH
+    ) (
+    input clk,    // clock
+    input rst,    // reset
+    input start,  // start calculation
+    input write_a,
+    output reg busy = 1'b0,   // calculation in progress
+    output  reg    done = 1'b0,   // calculation is complete (high for one tick)
+    output   reg   valid = 1'b0,  // result is valid
+    output   reg   dbz = 1'b0,    // divide by zero
+    output   reg   ovf = 1'b0,    // overflow
+    input signed [WIDTH-1:0] a_in,   // dividend (numerator)
+    input signed [WIDTH-1:0] b,   // divisor (denominator)
+    output reg signed [WIDTH-1:0] val = 32'd0 // result value: quotient
+    );
+
+
+    reg signed [WIDTH-1:0] a = 0;
+
+    always @(posedge clk)
+    begin
+        if (write_a)
+        begin
+            a <= a_in;
+        end
+        
+    end
+
+    localparam WIDTHU = WIDTH - 1;                 // unsigned widths are 1 bit narrower
+    localparam FBITSW = (FBITS == 0) ? 1 : FBITS;  // avoid negative vector width when FBITS=0
+    localparam SMALLEST = {1'b1, {WIDTHU{1'b0}}};  // smallest negative number
+
+    localparam ITER = WIDTHU + FBITS;  // iteration count: unsigned input width + fractional bits
+    reg [$clog2(ITER):0] i;          // iteration counter (allow ITER+1 iterations for rounding)
+
+    reg a_sig = 1'b0;
+    reg b_sig = 1'b0;
+    reg sig_diff = 1'b0;      // signs of inputs and whether different
+
+    reg [WIDTHU-1:0] au = 0;
+    reg [WIDTHU-1:0] bu = 0;         // absolute version of inputs (unsigned)
+
+    reg [WIDTHU-1:0] quo = 0;
+    reg [WIDTHU-1:0] quo_next = 0;  // intermediate quotients (unsigned)
+
+    reg [WIDTHU:0] acc = 0;
+    reg [WIDTHU:0] acc_next = 0;    // accumulator (unsigned but 1 bit wider)
+
+    // input signs
+    always @(*)
+    begin
+        a_sig = a[WIDTH-1+:1];
+        b_sig = b[WIDTH-1+:1];
+    end
+
+    // division algorithm iteration
+    always @(*)
+    begin
+        if (acc >= {1'b0, bu}) begin
+            acc_next = acc - bu;
+            {acc_next, quo_next} = {acc_next[WIDTHU-1:0], quo, 1'b1};
+        end else begin
+            {acc_next, quo_next} = {acc, quo} << 1;
+        end
+    end
+
+    // calculation state machine
+    parameter IDLE    = 5'd0;
+    parameter INIT    = 5'd1;
+    parameter CALC    = 5'd2;
+    parameter ROUND   = 5'd3;
+    parameter SIGN    = 5'd4;
+    parameter DONE    = 5'd5;
+
+    reg [2:0] state = IDLE;
+
+    always @(posedge clk) begin
+        done <= 0;
+        case (state)
+            INIT: begin
+                state <= CALC;
+                ovf <= 0;
+                i <= 0;
+                {acc, quo} <= {{WIDTHU{1'b0}}, au, 1'b0};  // initialize calculation
+            end
+            CALC: begin
+                if (i == WIDTHU-1 && quo_next[WIDTHU-1:WIDTHU-FBITSW] != 0) begin  // overflow
+                    state <= DONE;
+                    busy <= 0;
+                    done <= 1;
+                    ovf <= 1;
+                end else begin
+                    if (i == ITER-1) state <= ROUND;  // calculation complete after next iteration
+                    i <= i + 1;
+                    acc <= acc_next;
+                    quo <= quo_next;
+                end
+            end
+            ROUND: begin  // Gaussian rounding
+                state <= SIGN;
+                if (quo_next[0] == 1'b1) begin  // next digit is 1, so consider rounding
+                    // round up if quotient is odd or remainder is non-zero
+                    if (quo[0] == 1'b1 || acc_next[WIDTHU:1] != 0) quo <= quo + 1;
+                end
+            end
+            SIGN: begin  // adjust quotient sign if non-zero and input signs differ
+                state <= DONE;
+                if (quo != 0) val <= (sig_diff) ? {1'b1, -quo} : {1'b0, quo};
+                busy <= 0;
+                done <= 1;
+                valid <= 1;
+            end
+            DONE: begin
+                done <= 1;
+                state <= IDLE;
+            end
+            default: begin  // IDLE
+                if (start) begin
+                    valid <= 0;
+                    if (b == 0) begin  // divide by zero
+                        state <= DONE;
+                        busy <= 0;
+                        done <= 1;
+                        dbz <= 1;
+                        ovf <= 0;
+                    end else if (a == SMALLEST || b == SMALLEST) begin  // overflow
+                        state <= DONE;
+                        busy <= 0;
+                        done <= 1;
+                        dbz <= 0;
+                        ovf <= 1;
+                    end else begin
+                        state <= INIT;
+                        au <= (a_sig) ? -a[WIDTHU-1:0] : a[WIDTHU-1:0];  // register abs(a)
+                        bu <= (b_sig) ? -b[WIDTHU-1:0] : b[WIDTHU-1:0];  // register abs(b)
+                        sig_diff <= (a_sig ^ b_sig);  // register input sign difference
+                        busy <= 1;
+                        dbz <= 0;
+                        ovf <= 0;
+                    end
+                end
+            end
+        endcase
+        if (rst) begin
+            state <= IDLE;
+            busy <= 0;
+            done <= 0;
+            valid <= 0;
+            dbz <= 0;
+            ovf <= 0;
+            val <= 0;
+        end
+    end
+endmodule

+ 39 - 2
Verilog/modules/Memory/MemoryUnit.v

@@ -160,7 +160,9 @@ localparam
     //A_SNESPAD = 35,
     A_PS2 = 36,
     A_BOOTMODE = 37,
-    A_VRAMPX = 38;
+    A_VRAMPX = 38,
+    A_DIVWA = 39,
+    A_DIVSTART = 40;
 
 //------------
 //SPI0 (flash) TODO: move this to a separate module
@@ -525,6 +527,29 @@ Keyboard PS2Keyboard (
 );
 
 
+wire [31:0] div_input;
+wire div_write_a;
+wire div_busy;
+
+wire [31:0] div_val;
+
+
+Divider divider(
+.clk        (clk), 
+.rst        (reset),
+.start      (div_start),  // start calculation
+.write_a    (div_write_a),
+.busy       (div_busy),   // calculation in progress
+//.done       (div_done),   // calculation is complete (high for one tick)
+//.valid      (valid),  // result is valid
+//.dbz        (dbz),    // divide by zero
+//.ovf        (ovf),    // overflow
+.a_in       (bus_data),   // dividend (numerator)
+.b          (bus_data),   // divisor (denominator)
+.val        (div_val)  // result value: quotient
+);
+
+
 reg [31:0] bus_d_reg = 32'd0;
 
 //----
@@ -606,6 +631,9 @@ assign OST3_trigger     = (bus_addr == 27'hC0273E && bus_we);
 //SNES
 //assign SNES_start       = bus_addr == 27'hC0273F && bus_start;
 
+//Divider
+assign div_write_a      = (bus_addr == 27'hC02742 && bus_we);
+assign div_start        = (bus_addr == 27'hC02743 && bus_we);
 
 
 reg [5:0] a_sel;
@@ -652,6 +680,8 @@ begin
     //if (bus_addr == 27'hC0273F) a_sel = A_SNESPAD;
     if (bus_addr == 27'hC02740) a_sel = A_PS2;
     if (bus_addr == 27'hC02741) a_sel = A_BOOTMODE;
+    if (bus_addr == 27'hC02742) a_sel = A_DIVWA;
+    if (bus_addr == 27'hC02743) a_sel = A_DIVSTART;
     if (bus_addr >= 27'hD00000 && bus_addr < 27'hD12C00) a_sel = A_VRAMPX;
 end
 
@@ -698,7 +728,8 @@ begin
         //A_SNESPAD:      bus_q_wire = {16'd0, SNES_state};
         A_PS2:          bus_q_wire = {24'd0, PS2_scanCode};
         A_BOOTMODE:     bus_q_wire = {31'd0, boot_mode};
-        A_VRAMPX:      bus_q_wire = VRAMpx_cpu_q;
+        A_VRAMPX:       bus_q_wire = VRAMpx_cpu_q;
+        A_DIVSTART:     bus_q_wire = div_val;
         default:        bus_q_wire = 32'd0;
     endcase
 end
@@ -902,6 +933,12 @@ begin
                     bus_done <= 1'b1;
                 end
 
+                A_DIVSTART:
+                begin
+                    if (!div_busy)
+                        if (!bus_done_next) bus_done_next <= 1'b1;
+                end
+
                 default:
                 begin
                     if (!bus_done_next) bus_done_next <= 1'b1;

+ 43 - 0
Verilog/output/divider.gtkw

@@ -0,0 +1,43 @@
+[*]
+[*] GTKWave Analyzer v3.3.107 (w)1999-2020 BSI
+[*] Fri Sep 15 17:19:10 2023
+[*]
+[dumpfile] "/home/bart/Documents/FPGA/FPGC6/Verilog/output/wave.vcd"
+[dumpfile_mtime] "Fri Sep 15 17:05:26 2023"
+[dumpfile_size] 7596
+[savefile] "/home/bart/Documents/FPGA/FPGC6/Verilog/output/divider.gtkw"
+[timestart] 0
+[size] 1920 1054
+[pos] -1 -1
+*-8.000000 567 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
+[treeopen] divider_tb.
+[sst_width] 227
+[signals_width] 169
+[sst_expanded] 1
+[sst_vpaned_height] 293
+@28
+divider_tb.clk
+divider_tb.reset
+@200
+-
+@24
+divider_tb.a[31:0]
+divider_tb.b[31:0]
+divider_tb.val[31:0]
+divider_tb.val_int[15:0]
+@200
+-
+@22
+divider_tb.divider.a[31:0]
+@23
+divider_tb.divider.b[31:0]
+@28
+divider_tb.write_a
+divider_tb.start
+divider_tb.busy
+divider_tb.done
+divider_tb.valid
+divider_tb.dbz
+divider_tb.ovf
+[pattern_trace] 1
+[pattern_trace] 0

+ 1 - 0
Verilog/testbench/FPGC_tb.v

@@ -45,6 +45,7 @@
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/UARTrx.v"
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/SimpleSPI.v"
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/LEDvisualizer.v"
+`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/Divider.v"
 
 // gpu
 `include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/GPU/FSX.v"

+ 123 - 0
Verilog/testbench/divider_tb.v

@@ -0,0 +1,123 @@
+/*
+ * Testbench
+ * Simulation for divider module
+*/
+
+// Set timescale
+`timescale 1 ns/1 ns
+
+// Includes
+// Memory
+`include "/home/bart/Documents/FPGA/FPGC6/Verilog/modules/IO/Divider.v"
+
+
+// Define testmodule
+module divider_tb;
+
+// clock/reset I/O
+reg clk = 1'b0;
+reg reset = 1'b0;
+reg start = 1'b0;
+reg write_a = 1'b0;
+
+wire busy;
+wire done;
+wire valid;
+wire dbz;
+wire ovf;
+
+
+reg signed [31:0] a = 0;
+reg signed [31:0] b = 0;
+
+wire signed [31:0] val;
+
+wire signed [15:0] val_int;
+assign val_int = val [31:16];
+
+Divider divider(
+.clk    (clk), 
+.rst    (reset),
+.start(start),  // start calculation
+.write_a(write_a),
+.busy(busy),   // calculation in progress
+.done(done),   // calculation is complete (high for one tick)
+.valid(valid),  // result is valid
+.dbz(dbz),    // divide by zero
+.ovf(ovf),    // overflow
+.a_in(a),   // dividend (numerator)
+.b(b),   // divisor (denominator)
+.val(val)  // result value: quotient
+);
+
+
+
+initial
+begin
+    // dump everything for GTKwave
+    $dumpfile("/home/bart/Documents/FPGA/FPGC6/Verilog/output/wave.vcd");
+    $dumpvars;
+    
+    #10 
+
+    // startup
+    repeat(2)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+    reset = 1;
+
+    repeat(2)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+    reset = 0;
+
+    repeat(4)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+    a = 17 << 16;
+    write_a = 1;
+    repeat(1)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+    write_a = 0;
+
+    repeat(4)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+    a = 0;
+    b = 3 << 16;
+    start = 1;
+
+
+    repeat(64)
+    begin
+        clk = ~clk;
+        #10 clk = ~clk;
+        #10;
+    end
+
+
+    #1 $finish;
+end
+
+endmodule