add licenses and readme
authorJacob Lifshay <programmerjake@gmail.com>
Wed, 21 Mar 2018 01:19:21 +0000 (18:19 -0700)
committerJacob Lifshay <programmerjake@gmail.com>
Wed, 21 Mar 2018 01:19:21 +0000 (18:19 -0700)
32 files changed:
.gitignore [new file with mode: 0644]
ReadMe.md [new file with mode: 0644]
block_memory.v [new file with mode: 0644]
block_memory_16kbit.v [new file with mode: 0644]
cpu.bmm [new file with mode: 0644]
cpu.v [new file with mode: 0644]
cpu.vh [new file with mode: 0644]
cpu_alu.v [new file with mode: 0644]
cpu_decoder.v [new file with mode: 0644]
cpu_fetch_stage.v [new file with mode: 0644]
cpu_memory_interface.v [new file with mode: 0644]
font8x8.hex [new file with mode: 0644]
main.bit [new file with mode: 0644]
main.ucf [new file with mode: 0644]
main.v [new file with mode: 0644]
main_test.v [new file with mode: 0644]
riscv.vh [new file with mode: 0644]
rv32.xise [new file with mode: 0644]
software/.clang-format [new file with mode: 0644]
software/.gitignore [new file with mode: 0644]
software/Makefile [new file with mode: 0644]
software/main.cpp [new file with mode: 0644]
software/make_block_memory.sh [new file with mode: 0755]
software/ram.ld [new file with mode: 0644]
software/start.cpp [new file with mode: 0644]
software/startup.S [new file with mode: 0644]
text_initial.hex [new file with mode: 0644]
vga.v [new file with mode: 0644]
vga_clock_generator.v [new file with mode: 0644]
vga_font_generator.v [new file with mode: 0644]
vga_location_generator.v [new file with mode: 0644]
vga_text_buffer.v [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..20598f5
--- /dev/null
@@ -0,0 +1,77 @@
+/_ngo
+/bitgen.xmsgs
+/map.xmsgs
+/ngdbuild.xmsgs
+/par.xmsgs
+/trce.xmsgs
+/xst.xmsgs
+/core.bld
+/core.cmd_log
+/core.lso
+/core.ngc
+/core.ngd
+/core.ngr
+/core.prj
+/core.stx
+/core.syr
+/core.xst
+/core_map.map
+/core_map.mrp
+/core_ngdbuild.xrpt
+/core_summary.html
+/core_xst.xrpt
+/main.bgn
+/main.bld
+/main.cmd_log
+/main.drc
+/main.lso
+/main.mcs
+/main.ncd
+/main.ngc
+/main.ngd
+/main.ngr
+/main.pad
+/main.par
+/main.pcf
+/main.prj
+/main.prm
+/main.ptwx
+/main.stx
+/main.syr
+/main.twr
+/main.twx
+/main.unroutes
+/main.ut
+/main.v.cmd_log
+/main.v.prj
+/main.v.stx
+/main.v.syr
+/main.v.xst
+/main.v_summary.html
+/main.v_xst.xrpt
+/main.xpi
+/main.xst
+/main_envsettings.html
+/main_map.map
+/main_map.mrp
+/main_map.ncd
+/main_map.ngm
+/main_map.xrpt
+/main_ngdbuild.xrpt
+/main_pad.csv
+/main_pad.txt
+/main_par.xrpt
+/main_preroute.twr
+/main_preroute.twx
+/main_summary.html
+/main_summary.xml
+/main_usage.xml
+/main_xst.xrpt
+/planAhead_run_1
+/planAhead_run_2
+/usage_statistics_webtalk.html
+/webtalk.log
+/webtalk_pn.xml
+/xlnx_auto_0_xdb
+/xst
+/output.bit
diff --git a/ReadMe.md b/ReadMe.md
new file mode 100644 (file)
index 0000000..e777adb
--- /dev/null
+++ b/ReadMe.md
@@ -0,0 +1,64 @@
+# 32-bit RISC-V processor design
+
+Implements RV32I instruction set except for interrupts and some CSRs.
+
+Warning: CSR and system instructions weren't really tested so may not work properly
+
+Default software runs a 2.5D maze game through the VGA port, using SW2 and SW3 to turn and move.
+
+Implemented CSRs:
+- cycle/cycleh -- doesn't count
+- time/timeh -- doesn't count
+- instret/instreth -- doesn't count
+- mvendorid
+- marchid
+- mimpid
+- misa -- ignores writes
+- mstatus -- all but mpie and mie are hardwired
+- mie -- all but meie, mtie, and msie are hardwired
+- mtvec -- hardwired to 0x10040
+- mscratch
+- mepc
+- mcause
+- mip -- ignores writes
+
+- used FPGA: ChinaQMTECH's QM_XC6SLX16_DDR3 board with the vga output board. [Docs](https://raw.githubusercontent.com/ChinaQMTECH/QM_XC6SLX16_DDR3/master/QM_XC6SLX16_DDR3_V02.zip) [archived on archive.org](http://web.archive.org/web/20180321000346/https://raw.githubusercontent.com/ChinaQMTECH/QM_XC6SLX16_DDR3/master/QM_XC6SLX16_DDR3_V02.zip)
+- used programmer: Digilent's Hs2 JTAG programmer
+
+## Building (On Ubuntu 16.04)
+Requires Xilinx's ISE v. 14.7 to be installed in /opt/Xilinx (just leave the default installation directory)
+
+    sudo apt-get install git g++ autoconf automake autotools-dev curl libmpc-dev libmpfr-dev libgmp-dev gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev
+    sudo mkdir /opt/riscv
+    sudo chown $USER /opt/riscv # so you don't need root when building; you can change back after building riscv-gnu-toolchain
+    git clone --recursive https://github.com/riscv/riscv-gnu-toolchain.git
+    export PATH=/opt/riscv/bin:"$PATH"
+    cd riscv-gnu-toolchain
+    ./configure --prefix=/opt/riscv --with-arch=rv32i
+    make
+    sudo chown -R root:root /opt/riscv # change owner back to root as the compiler is finished installing
+    cd ..
+    git clone https://github.com/programmerjake/rv32.git
+    cd rv32/software
+    make
+    cd ..
+    # at this point the built bitstream is in output.bit
+    djtgcfg prog -d JtagHS2 -i 0 -f output.bit # program the FPGA
+
+## Building the hardware (only required if verilog source is modified)
+
+Requires having built the software at least once to generate the ram initialization files.
+
+Run `(. /opt/Xilinx/14.7/ISE_DS/settings64.sh; ise&)` in a terminal.  
+Switch the view to Implementation  
+Select main.v  
+Run "Generate Programming File"  
+Open a terminal and run:
+
+    export PATH=/opt/riscv/bin:"$PATH"
+    cd rv32/software
+    make
+    cd ..
+    # at this point the built bitstream is in output.bit
+    djtgcfg prog -d JtagHS2 -i 0 -f output.bit # program the FPGA
+
diff --git a/block_memory.v b/block_memory.v
new file mode 100644 (file)
index 0000000..bc472bb
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+
+module block_memory(
+    input clk,
+    input [31:0] a_ram_address,
+    input [3:0] a_write_enable,
+    input [31:0] a_write_input,
+    output reg [31:0] a_read_output,
+    input [31:0] b_ram_address,
+    output reg [31:0] b_read_output
+    );
+
+    wire a_enable_0 = a_ram_address[31:11] == 0;
+    wire b_enable_0 = b_ram_address[31:11] == 0;
+    wire [3:0] a_write_enable_0 = {4{a_enable_0}} & a_write_enable;
+    wire [31:0] a_read_output_0;
+    wire [31:0] b_read_output_0;
+    block_memory_16kbit #(
+        .initial_file("software/ram_0_byte0.hex")
+        ) ram_0_byte0(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_0[0]),
+        .port_a_write_input(a_write_input[7:0]),
+        .port_a_read_output(a_read_output_0[7:0]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_0[7:0])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_0_byte1.hex")
+        ) ram_0_byte1(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_0[1]),
+        .port_a_write_input(a_write_input[15:8]),
+        .port_a_read_output(a_read_output_0[15:8]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_0[15:8])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_0_byte2.hex")
+        ) ram_0_byte2(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_0[2]),
+        .port_a_write_input(a_write_input[23:16]),
+        .port_a_read_output(a_read_output_0[23:16]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_0[23:16])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_0_byte3.hex")
+        ) ram_0_byte3(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_0[3]),
+        .port_a_write_input(a_write_input[31:24]),
+        .port_a_read_output(a_read_output_0[31:24]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_0[31:24])
+        );
+
+
+    wire a_enable_1 = a_ram_address[31:11] == 1;
+    wire b_enable_1 = b_ram_address[31:11] == 1;
+    wire [3:0] a_write_enable_1 = {4{a_enable_1}} & a_write_enable;
+    wire [31:0] a_read_output_1;
+    wire [31:0] b_read_output_1;
+    block_memory_16kbit #(
+        .initial_file("software/ram_1_byte0.hex")
+        ) ram_1_byte0(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_1[0]),
+        .port_a_write_input(a_write_input[7:0]),
+        .port_a_read_output(a_read_output_1[7:0]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_1[7:0])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_1_byte1.hex")
+        ) ram_1_byte1(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_1[1]),
+        .port_a_write_input(a_write_input[15:8]),
+        .port_a_read_output(a_read_output_1[15:8]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_1[15:8])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_1_byte2.hex")
+        ) ram_1_byte2(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_1[2]),
+        .port_a_write_input(a_write_input[23:16]),
+        .port_a_read_output(a_read_output_1[23:16]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_1[23:16])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_1_byte3.hex")
+        ) ram_1_byte3(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_1[3]),
+        .port_a_write_input(a_write_input[31:24]),
+        .port_a_read_output(a_read_output_1[31:24]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_1[31:24])
+        );
+
+
+    wire a_enable_2 = a_ram_address[31:11] == 2;
+    wire b_enable_2 = b_ram_address[31:11] == 2;
+    wire [3:0] a_write_enable_2 = {4{a_enable_2}} & a_write_enable;
+    wire [31:0] a_read_output_2;
+    wire [31:0] b_read_output_2;
+    block_memory_16kbit #(
+        .initial_file("software/ram_2_byte0.hex")
+        ) ram_2_byte0(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_2[0]),
+        .port_a_write_input(a_write_input[7:0]),
+        .port_a_read_output(a_read_output_2[7:0]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_2[7:0])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_2_byte1.hex")
+        ) ram_2_byte1(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_2[1]),
+        .port_a_write_input(a_write_input[15:8]),
+        .port_a_read_output(a_read_output_2[15:8]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_2[15:8])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_2_byte2.hex")
+        ) ram_2_byte2(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_2[2]),
+        .port_a_write_input(a_write_input[23:16]),
+        .port_a_read_output(a_read_output_2[23:16]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_2[23:16])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_2_byte3.hex")
+        ) ram_2_byte3(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_2[3]),
+        .port_a_write_input(a_write_input[31:24]),
+        .port_a_read_output(a_read_output_2[31:24]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_2[31:24])
+        );
+
+
+    wire a_enable_3 = a_ram_address[31:11] == 3;
+    wire b_enable_3 = b_ram_address[31:11] == 3;
+    wire [3:0] a_write_enable_3 = {4{a_enable_3}} & a_write_enable;
+    wire [31:0] a_read_output_3;
+    wire [31:0] b_read_output_3;
+    block_memory_16kbit #(
+        .initial_file("software/ram_3_byte0.hex")
+        ) ram_3_byte0(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_3[0]),
+        .port_a_write_input(a_write_input[7:0]),
+        .port_a_read_output(a_read_output_3[7:0]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_3[7:0])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_3_byte1.hex")
+        ) ram_3_byte1(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_3[1]),
+        .port_a_write_input(a_write_input[15:8]),
+        .port_a_read_output(a_read_output_3[15:8]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_3[15:8])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_3_byte2.hex")
+        ) ram_3_byte2(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_3[2]),
+        .port_a_write_input(a_write_input[23:16]),
+        .port_a_read_output(a_read_output_3[23:16]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_3[23:16])
+        );
+
+    block_memory_16kbit #(
+        .initial_file("software/ram_3_byte3.hex")
+        ) ram_3_byte3(
+        .clk(clk),
+        .port_a_address(a_ram_address[10:0]),
+        .port_a_write_enable(a_write_enable_3[3]),
+        .port_a_write_input(a_write_input[31:24]),
+        .port_a_read_output(a_read_output_3[31:24]),
+        .port_b_address(b_ram_address[10:0]),
+        .port_b_read_output(b_read_output_3[31:24])
+        );
+
+
+    always @* begin
+        case(a_ram_address[31:11])
+        0: a_read_output = a_read_output_0;
+        1: a_read_output = a_read_output_1;
+        2: a_read_output = a_read_output_2;
+        3: a_read_output = a_read_output_3;
+        default: a_read_output = 32'hXXXXXXXX;
+        endcase
+    end
+
+    always @* begin
+        case(b_ram_address[31:11])
+        0: b_read_output = b_read_output_0;
+        1: b_read_output = b_read_output_1;
+        2: b_read_output = b_read_output_2;
+        3: b_read_output = b_read_output_3;
+        default: b_read_output = 32'hXXXXXXXX;
+        endcase
+    end
+endmodule
diff --git a/block_memory_16kbit.v b/block_memory_16kbit.v
new file mode 100644 (file)
index 0000000..092d00a
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+module block_memory_16kbit(
+    input clk,
+    input [10:0] port_a_address,
+    input port_a_write_enable,
+    input [7:0] port_a_write_input,
+    output [7:0] port_a_read_output,
+    input [10:0] port_b_address,
+    output [7:0] port_b_read_output
+    );
+    
+    parameter initial_file = "";
+
+    (* ram_style = "block" *)
+    reg [7:0] ram[{11{1'b1}} : 0];
+    
+    initial $readmemh(initial_file, ram);
+
+    reg [7:0] port_a_read_output_reg;
+    reg [7:0] port_b_read_output_reg;
+            
+    always @(posedge clk) begin
+        port_b_read_output_reg <= ram[port_b_address];
+        if(port_a_write_enable) begin
+            ram[port_a_address] <= port_a_write_input;
+        end
+        else begin
+            port_a_read_output_reg <= ram[port_a_address];
+        end
+    end
+    
+    assign port_a_read_output = port_a_read_output_reg;
+    assign port_b_read_output = port_b_read_output_reg;
+
+endmodule
diff --git a/cpu.bmm b/cpu.bmm
new file mode 100644 (file)
index 0000000..a92e577
--- /dev/null
+++ b/cpu.bmm
@@ -0,0 +1,34 @@
+ADDRESS_SPACE ram COMBINED [0x10000:0x17FFF]
+    ADDRESS_RANGE RAMB16
+        BUS_BLOCK
+            cpu1/memory_interface/ram/ram_0_byte0/Mram_ram [7:0] LOC = X0Y30;
+            cpu1/memory_interface/ram/ram_0_byte1/Mram_ram [15:8] LOC = X0Y22;
+            cpu1/memory_interface/ram/ram_0_byte2/Mram_ram [23:16] LOC = X1Y30;
+            cpu1/memory_interface/ram/ram_0_byte3/Mram_ram [31:24] LOC = X1Y22;
+        END_BUS_BLOCK;
+    END_ADDRESS_RANGE;
+    ADDRESS_RANGE RAMB16
+        BUS_BLOCK
+            cpu1/memory_interface/ram/ram_1_byte0/Mram_ram [7:0] LOC = X0Y28;
+            cpu1/memory_interface/ram/ram_1_byte1/Mram_ram [15:8] LOC = X0Y20;
+            cpu1/memory_interface/ram/ram_1_byte2/Mram_ram [23:16] LOC = X1Y28;
+            cpu1/memory_interface/ram/ram_1_byte3/Mram_ram [31:24] LOC = X1Y20;
+        END_BUS_BLOCK;
+    END_ADDRESS_RANGE;
+    ADDRESS_RANGE RAMB16
+        BUS_BLOCK
+            cpu1/memory_interface/ram/ram_2_byte0/Mram_ram [7:0] LOC = X0Y26;
+            cpu1/memory_interface/ram/ram_2_byte1/Mram_ram [15:8] LOC = X0Y18;
+            cpu1/memory_interface/ram/ram_2_byte2/Mram_ram [23:16] LOC = X1Y26;
+            cpu1/memory_interface/ram/ram_2_byte3/Mram_ram [31:24] LOC = X1Y18;
+        END_BUS_BLOCK;
+    END_ADDRESS_RANGE;
+    ADDRESS_RANGE RAMB16
+        BUS_BLOCK
+            cpu1/memory_interface/ram/ram_3_byte0/Mram_ram [7:0] LOC = X0Y24;
+            cpu1/memory_interface/ram/ram_3_byte1/Mram_ram [15:8] LOC = X0Y16;
+            cpu1/memory_interface/ram/ram_3_byte2/Mram_ram [23:16] LOC = X1Y24;
+            cpu1/memory_interface/ram/ram_3_byte3/Mram_ram [31:24] LOC = X1Y16;
+        END_BUS_BLOCK;
+    END_ADDRESS_RANGE;
+END_ADDRESS_SPACE;
diff --git a/cpu.v b/cpu.v
new file mode 100644 (file)
index 0000000..b2a4a81
--- /dev/null
+++ b/cpu.v
@@ -0,0 +1,771 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+`include "riscv.vh"
+`include "cpu.vh"
+
+module cpu(
+    input clk,
+    input reset,
+    output tty_write,
+    output [7:0] tty_write_data,
+    input tty_write_busy,
+    input switch_2,
+    input switch_3,
+    output led_1,
+    output led_3
+    );
+
+    parameter ram_size = 'h8000;
+    parameter ram_start = 32'h1_0000;
+    parameter reset_vector = ram_start;
+    parameter mtvec = ram_start + 'h40;
+
+    reg [31:0] registers[31:1];
+
+    wire [31:2] memory_interface_fetch_address;
+    wire [31:0] memory_interface_fetch_data;
+    wire memory_interface_fetch_valid;
+    wire [31:2] memory_interface_rw_address;
+    wire [3:0] memory_interface_rw_byte_mask;
+    wire memory_interface_rw_read_not_write;
+    wire memory_interface_rw_active;
+    wire [31:0] memory_interface_rw_data_in;
+    wire [31:0] memory_interface_rw_data_out;
+    wire memory_interface_rw_address_valid;
+    wire memory_interface_rw_wait;
+
+    cpu_memory_interface #(
+        .ram_size(ram_size),
+        .ram_start(ram_start)
+        ) memory_interface(
+        .clk(clk),
+        .reset(reset),
+        .fetch_address(memory_interface_fetch_address),
+        .fetch_data(memory_interface_fetch_data),
+        .fetch_valid(memory_interface_fetch_valid),
+        .rw_address(memory_interface_rw_address),
+        .rw_byte_mask(memory_interface_rw_byte_mask),
+        .rw_read_not_write(memory_interface_rw_read_not_write),
+        .rw_active(memory_interface_rw_active),
+        .rw_data_in(memory_interface_rw_data_in),
+        .rw_data_out(memory_interface_rw_data_out),
+        .rw_address_valid(memory_interface_rw_address_valid),
+        .rw_wait(memory_interface_rw_wait),
+        .tty_write(tty_write),
+        .tty_write_data(tty_write_data),
+        .tty_write_busy(tty_write_busy),
+        .switch_2(switch_2),
+        .switch_3(switch_3),
+        .led_1(led_1),
+        .led_3(led_3)
+        );
+
+    wire `fetch_action fetch_action;
+    wire [31:0] fetch_target_pc;
+    wire [31:0] fetch_output_pc;
+    wire [31:0] fetch_output_instruction;
+    wire `fetch_output_state fetch_output_state;
+
+    cpu_fetch_stage #(
+        .reset_vector(reset_vector),
+        .mtvec(mtvec)
+        ) fetch_stage(
+        .clk(clk),
+        .reset(reset),
+        .memory_interface_fetch_address(memory_interface_fetch_address),
+        .memory_interface_fetch_data(memory_interface_fetch_data),
+        .memory_interface_fetch_valid(memory_interface_fetch_valid),
+        .fetch_action(fetch_action),
+        .target_pc(fetch_target_pc),
+        .output_pc(fetch_output_pc),
+        .output_instruction(fetch_output_instruction),
+        .output_state(fetch_output_state)
+        );
+
+    wire [6:0] decoder_funct7;
+    wire [2:0] decoder_funct3;
+    wire [4:0] decoder_rd;
+    wire [4:0] decoder_rs1;
+    wire [4:0] decoder_rs2;
+    wire [31:0] decoder_immediate;
+    wire [6:0] decoder_opcode;
+    wire `decode_action decode_action;
+
+    cpu_decoder decoder(
+        .instruction(fetch_output_instruction),
+        .funct7(decoder_funct7),
+        .funct3(decoder_funct3),
+        .rd(decoder_rd),
+        .rs1(decoder_rs1),
+        .rs2(decoder_rs2),
+        .immediate(decoder_immediate),
+        .opcode(decoder_opcode),
+        .decode_action(decode_action));
+
+    wire [31:0] register_rs1 = (decoder_rs1 == 0) ? 0 : registers[decoder_rs1];
+    wire [31:0] register_rs2 = (decoder_rs2 == 0) ? 0 : registers[decoder_rs2];
+
+    wire [31:0] load_store_address = decoder_immediate + register_rs1;
+
+    wire [1:0] load_store_address_low_2 = decoder_immediate[1:0] + register_rs1[1:0];
+
+    function get_load_store_misaligned(
+        input [2:0] funct3,
+        input [1:0] load_store_address_low_2
+        );
+    begin
+        case(funct3[1:0])
+        `funct3_sb:
+            get_load_store_misaligned = 0;
+        `funct3_sh:
+            get_load_store_misaligned = load_store_address_low_2[0] != 0;
+        `funct3_sw:
+            get_load_store_misaligned = load_store_address_low_2[1:0] != 0;
+        default:
+            get_load_store_misaligned = 1'bX;
+        endcase
+    end
+    endfunction
+
+    wire load_store_misaligned = get_load_store_misaligned(decoder_funct3, load_store_address_low_2);
+
+    assign memory_interface_rw_address = load_store_address[31:2];
+
+    wire [3:0] unshifted_load_store_byte_mask = {decoder_funct3[1] ? 2'b11 : 2'b00, (decoder_funct3[1] | decoder_funct3[0]) ? 1'b1 : 1'b0, 1'b1};
+
+    assign memory_interface_rw_byte_mask = unshifted_load_store_byte_mask << load_store_address_low_2;
+
+    assign memory_interface_rw_data_in[31:24] = load_store_address_low_2[1]
+                                                ? (load_store_address_low_2[0] ? register_rs2[7:0] : register_rs2[15:8])
+                                                : (load_store_address_low_2[0] ? register_rs2[23:16] : register_rs2[31:24]);
+    assign memory_interface_rw_data_in[23:16] = load_store_address_low_2[1] ? register_rs2[7:0] : register_rs2[23:16];
+    assign memory_interface_rw_data_in[15:8] = load_store_address_low_2[0] ? register_rs2[7:0] : register_rs2[15:8];
+    assign memory_interface_rw_data_in[7:0] = register_rs2[7:0];
+
+    wire [31:0] unmasked_loaded_value;
+
+    assign unmasked_loaded_value[7:0] = load_store_address_low_2[1]
+                                        ? (load_store_address_low_2[0] ? memory_interface_rw_data_out[31:24] : memory_interface_rw_data_out[23:16])
+                                        : (load_store_address_low_2[0] ? memory_interface_rw_data_out[15:8] : memory_interface_rw_data_out[7:0]);
+    assign unmasked_loaded_value[15:8] = load_store_address_low_2[1] ? memory_interface_rw_data_out[31:24] : memory_interface_rw_data_out[15:8];
+    assign unmasked_loaded_value[31:16] = memory_interface_rw_data_out[31:16];
+
+    wire [31:0] loaded_value;
+
+    assign loaded_value[7:0] = unmasked_loaded_value[7:0];
+    assign loaded_value[15:8] = decoder_funct3[1:0] == 0 ? ({8{~decoder_funct3[2] & unmasked_loaded_value[7]}}) : unmasked_loaded_value[15:8];
+    assign loaded_value[31:16] = decoder_funct3[1] == 0 ? ({16{~decoder_funct3[2] & (decoder_funct3[0] ? unmasked_loaded_value[15] : unmasked_loaded_value[7])}}) : unmasked_loaded_value[31:16];
+
+    assign memory_interface_rw_active = ~reset
+                                        & (fetch_output_state == `fetch_output_state_valid)
+                                        & ~load_store_misaligned
+                                        & ((decode_action & (`decode_action_load | `decode_action_store)) != 0);
+
+    assign memory_interface_rw_read_not_write = ~decoder_opcode[5];
+
+    wire [31:0] alu_a = register_rs1;
+    wire [31:0] alu_b = decoder_opcode[5] ? register_rs2 : decoder_immediate;
+    wire [31:0] alu_result;
+
+    cpu_alu alu(
+        .funct7(decoder_funct7),
+        .funct3(decoder_funct3),
+        .opcode(decoder_opcode),
+        .a(alu_a),
+        .b(alu_b),
+        .result(alu_result)
+        );
+
+    wire [31:0] lui_auipc_result = decoder_opcode[5] ? decoder_immediate : decoder_immediate + fetch_output_pc;
+
+    assign fetch_target_pc[31:1] = ((decoder_opcode != `opcode_jalr ? fetch_output_pc[31:1] : register_rs1[31:1]) + decoder_immediate[31:1]);
+    assign fetch_target_pc[0] = 0;
+
+    wire misaligned_jump_target = fetch_target_pc[1];
+
+    wire [31:0] branch_arg_a = {register_rs1[31] ^ ~decoder_funct3[1], register_rs1[30:0]};
+    wire [31:0] branch_arg_b = {register_rs2[31] ^ ~decoder_funct3[1], register_rs2[30:0]};
+
+    wire branch_taken = decoder_funct3[0] ^ (decoder_funct3[2] ? branch_arg_a < branch_arg_b : branch_arg_a == branch_arg_b);
+
+    reg [31:0] mcause = 0;
+    reg [31:0] mepc = 32'hXXXXXXXX;
+    reg [31:0] mscratch = 32'hXXXXXXXX;
+
+    reg mstatus_mpie = 1'bX;
+    reg mstatus_mie = 0;
+    parameter mstatus_mprv = 0;
+    parameter mstatus_tsr = 0;
+    parameter mstatus_tw = 0;
+    parameter mstatus_tvm = 0;
+    parameter mstatus_mxr = 0;
+    parameter mstatus_sum = 0;
+    parameter mstatus_xs = 0;
+    parameter mstatus_fs = 0;
+    parameter mstatus_mpp = 2'b11;
+    parameter mstatus_spp = 0;
+    parameter mstatus_spie = 0;
+    parameter mstatus_upie = 0;
+    parameter mstatus_sie = 0;
+    parameter mstatus_uie = 0;
+
+    reg mie_meie = 1'bX;
+    reg mie_mtie = 1'bX;
+    reg mie_msie = 1'bX;
+    parameter mie_seie = 0;
+    parameter mie_ueie = 0;
+    parameter mie_stie = 0;
+    parameter mie_utie = 0;
+    parameter mie_ssie = 0;
+    parameter mie_usie = 0;
+
+    task reset_to_initial;
+    begin
+        mcause = 0;
+        mepc = 32'hXXXXXXXX;
+        mscratch = 32'hXXXXXXXX;
+        mstatus_mie = 0;
+        mstatus_mpie = 1'bX;
+        mie_meie = 1'bX;
+        mie_mtie = 1'bX;
+        mie_msie = 1'bX;
+        registers['h01] <= 32'hXXXXXXXX;
+        registers['h02] <= 32'hXXXXXXXX;
+        registers['h03] <= 32'hXXXXXXXX;
+        registers['h04] <= 32'hXXXXXXXX;
+        registers['h05] <= 32'hXXXXXXXX;
+        registers['h06] <= 32'hXXXXXXXX;
+        registers['h07] <= 32'hXXXXXXXX;
+        registers['h08] <= 32'hXXXXXXXX;
+        registers['h09] <= 32'hXXXXXXXX;
+        registers['h0A] <= 32'hXXXXXXXX;
+        registers['h0B] <= 32'hXXXXXXXX;
+        registers['h0C] <= 32'hXXXXXXXX;
+        registers['h0D] <= 32'hXXXXXXXX;
+        registers['h0E] <= 32'hXXXXXXXX;
+        registers['h0F] <= 32'hXXXXXXXX;
+        registers['h10] <= 32'hXXXXXXXX;
+        registers['h11] <= 32'hXXXXXXXX;
+        registers['h12] <= 32'hXXXXXXXX;
+        registers['h13] <= 32'hXXXXXXXX;
+        registers['h14] <= 32'hXXXXXXXX;
+        registers['h15] <= 32'hXXXXXXXX;
+        registers['h16] <= 32'hXXXXXXXX;
+        registers['h17] <= 32'hXXXXXXXX;
+        registers['h18] <= 32'hXXXXXXXX;
+        registers['h19] <= 32'hXXXXXXXX;
+        registers['h1A] <= 32'hXXXXXXXX;
+        registers['h1B] <= 32'hXXXXXXXX;
+        registers['h1C] <= 32'hXXXXXXXX;
+        registers['h1D] <= 32'hXXXXXXXX;
+        registers['h1E] <= 32'hXXXXXXXX;
+        registers['h1F] <= 32'hXXXXXXXX;
+    end
+    endtask
+
+    task write_register(input [4:0] register_number, input [31:0] value);
+    begin
+        if(register_number != 0)
+            registers[register_number] <= value;
+    end
+    endtask
+
+    function [31:0] evaluate_csr_funct3_operation(input [2:0] funct3, input [31:0] previous_value, input [31:0] written_value);
+    begin
+        case(funct3)
+        `funct3_csrrw, `funct3_csrrwi:
+            evaluate_csr_funct3_operation = written_value;
+        `funct3_csrrs, `funct3_csrrsi:
+            evaluate_csr_funct3_operation = written_value | previous_value;
+        `funct3_csrrc, `funct3_csrrci:
+            evaluate_csr_funct3_operation = ~written_value & previous_value;
+        default:
+            evaluate_csr_funct3_operation = 32'hXXXXXXXX;
+        endcase
+    end
+    endfunction
+
+    parameter misa_a = 1'b0;
+    parameter misa_b = 1'b0;
+    parameter misa_c = 1'b0;
+    parameter misa_d = 1'b0;
+    parameter misa_e = 1'b0;
+    parameter misa_f = 1'b0;
+    parameter misa_g = 1'b0;
+    parameter misa_h = 1'b0;
+    parameter misa_i = 1'b1;
+    parameter misa_j = 1'b0;
+    parameter misa_k = 1'b0;
+    parameter misa_l = 1'b0;
+    parameter misa_m = 1'b0;
+    parameter misa_n = 1'b0;
+    parameter misa_o = 1'b0;
+    parameter misa_p = 1'b0;
+    parameter misa_q = 1'b0;
+    parameter misa_r = 1'b0;
+    parameter misa_s = 1'b0;
+    parameter misa_t = 1'b0;
+    parameter misa_u = 1'b0;
+    parameter misa_v = 1'b0;
+    parameter misa_w = 1'b0;
+    parameter misa_x = 1'b0;
+    parameter misa_y = 1'b0;
+    parameter misa_z = 1'b0;
+    parameter misa = {
+        2'b01,
+        4'b0,
+        misa_z,
+        misa_y,
+        misa_x,
+        misa_w,
+        misa_v,
+        misa_u,
+        misa_t,
+        misa_s,
+        misa_r,
+        misa_q,
+        misa_p,
+        misa_o,
+        misa_n,
+        misa_m,
+        misa_l,
+        misa_k,
+        misa_j,
+        misa_i,
+        misa_h,
+        misa_g,
+        misa_f,
+        misa_e,
+        misa_d,
+        misa_c,
+        misa_b,
+        misa_a};
+
+    parameter mvendorid = 32'b0;
+    parameter marchid = 32'b0;
+    parameter mimpid = 32'b0;
+    parameter mhartid = 32'b0;
+
+    function [31:0] make_mstatus(input mstatus_tsr,
+        input mstatus_tw,
+        input mstatus_tvm,
+        input mstatus_mxr,
+        input mstatus_sum,
+        input mstatus_mprv,
+        input [1:0] mstatus_xs,
+        input [1:0] mstatus_fs,
+        input [1:0] mstatus_mpp,
+        input mstatus_spp,
+        input mstatus_mpie,
+        input mstatus_spie,
+        input mstatus_upie,
+        input mstatus_mie,
+        input mstatus_sie,
+        input mstatus_uie);
+    begin
+        make_mstatus = {(mstatus_xs == 2'b11) | (mstatus_fs == 2'b11),
+            8'b0,
+            mstatus_tsr,
+            mstatus_tw,
+            mstatus_tvm,
+            mstatus_mxr,
+            mstatus_sum,
+            mstatus_mprv,
+            mstatus_xs,
+            mstatus_fs,
+            mstatus_mpp,
+            2'b0,
+            mstatus_spp,
+            mstatus_mpie,
+            1'b0,
+            mstatus_spie,
+            mstatus_upie,
+            mstatus_mie,
+            1'b0,
+            mstatus_sie,
+            mstatus_uie};
+    end
+    endfunction
+
+    wire mip_meip = 0; // TODO: implement external interrupts
+    parameter mip_seip = 0;
+    parameter mip_ueip = 0;
+    wire mip_mtip = 0; // TODO: implement timer interrupts
+    parameter mip_stip = 0;
+    parameter mip_utip = 0;
+    parameter mip_msip = 0;
+    parameter mip_ssip = 0;
+    parameter mip_usip = 0;
+
+    wire csr_op_is_valid;
+
+    function `fetch_action get_fetch_action(
+        input `fetch_output_state fetch_output_state,
+        input `decode_action decode_action,
+        input load_store_misaligned,
+        input memory_interface_rw_address_valid,
+        input memory_interface_rw_wait,
+        input branch_taken,
+        input misaligned_jump_target,
+        input csr_op_is_valid
+        );
+    begin
+        case(fetch_output_state)
+        `fetch_output_state_empty:
+            get_fetch_action = `fetch_action_default;
+        `fetch_output_state_trap:
+            get_fetch_action = `fetch_action_ack_trap;
+        `fetch_output_state_valid: begin
+            if((decode_action & `decode_action_trap_illegal_instruction) != 0) begin
+                get_fetch_action = `fetch_action_error_trap;
+            end
+            else if((decode_action & `decode_action_trap_ecall_ebreak) != 0) begin
+                get_fetch_action = `fetch_action_noerror_trap;
+            end
+            else if((decode_action & (`decode_action_load | `decode_action_store)) != 0) begin
+                if(load_store_misaligned | ~memory_interface_rw_address_valid) begin
+                    get_fetch_action = `fetch_action_error_trap;
+                end
+                else if(memory_interface_rw_wait) begin
+                    get_fetch_action = `fetch_action_wait;
+                end
+                else begin
+                    get_fetch_action = `fetch_action_default;
+                end
+            end
+            else if((decode_action & `decode_action_fence_i) != 0) begin
+                get_fetch_action = `fetch_action_fence;
+            end
+            else if((decode_action & `decode_action_branch) != 0) begin
+                if(branch_taken) begin
+                    if(misaligned_jump_target) begin
+                        get_fetch_action = `fetch_action_error_trap;
+                    end
+                    else begin
+                        get_fetch_action = `fetch_action_jump;
+                    end
+                end
+                else
+                begin
+                    get_fetch_action = `fetch_action_default;
+                end
+            end
+            else if((decode_action & (`decode_action_jal | `decode_action_jalr)) != 0) begin
+                if(misaligned_jump_target) begin
+                    get_fetch_action = `fetch_action_error_trap;
+                end
+                else begin
+                    get_fetch_action = `fetch_action_jump;
+                end
+            end
+            else if((decode_action & `decode_action_csr) != 0) begin
+                if(csr_op_is_valid)
+                    get_fetch_action = `fetch_action_default;
+                else
+                    get_fetch_action = `fetch_action_error_trap;
+            end
+            else begin
+                get_fetch_action = `fetch_action_default;
+            end
+        end
+        default:
+            get_fetch_action = 32'hXXXXXXXX;
+        endcase
+    end
+    endfunction
+
+    assign fetch_action = get_fetch_action(
+        fetch_output_state,
+        decode_action,
+        load_store_misaligned,
+        memory_interface_rw_address_valid,
+        memory_interface_rw_wait,
+        branch_taken,
+        misaligned_jump_target,
+        csr_op_is_valid
+        );
+
+    task handle_trap;
+    begin
+        mstatus_mpie = mstatus_mie;
+        mstatus_mie = 0;
+        mepc = (fetch_action == `fetch_action_noerror_trap) ? fetch_output_pc + 4 : fetch_output_pc;
+        if(fetch_action == `fetch_action_ack_trap) begin
+            mcause = `cause_instruction_access_fault;
+        end
+        else if((decode_action & `decode_action_trap_illegal_instruction) != 0) begin
+            mcause = `cause_illegal_instruction;
+        end
+        else if((decode_action & `decode_action_trap_ecall_ebreak) != 0) begin
+            mcause = decoder_immediate[0] ? `cause_machine_environment_call : `cause_breakpoint;
+        end
+        else if((decode_action & `decode_action_load) != 0) begin
+            if(load_store_misaligned)
+                mcause = `cause_load_address_misaligned;
+            else
+                mcause = `cause_load_access_fault;
+        end
+        else if((decode_action & `decode_action_store) != 0) begin
+            if(load_store_misaligned)
+                mcause = `cause_store_amo_address_misaligned;
+            else
+                mcause = `cause_store_amo_access_fault;
+        end
+        else if((decode_action & (`decode_action_branch | `decode_action_jal | `decode_action_jalr)) != 0) begin
+            mcause = `cause_instruction_address_misaligned;
+        end
+        else begin
+            mcause = `cause_illegal_instruction;
+        end
+    end
+    endtask
+
+    wire [11:0] csr_number = decoder_immediate;
+    wire [31:0] csr_input_value = decoder_funct3[2] ? decoder_rs1 : register_rs1;
+    wire csr_reads = decoder_funct3[1] | (decoder_rd != 0);
+    wire csr_writes = ~decoder_funct3[1] | (decoder_rs1 != 0);
+
+    function get_csr_op_is_valid(input [11:0] csr_number, input csr_reads, input csr_writes);
+    begin
+        case(csr_number)
+        `csr_ustatus,
+        `csr_fflags,
+        `csr_frm,
+        `csr_fcsr,
+        `csr_uie,
+        `csr_utvec,
+        `csr_uscratch,
+        `csr_uepc,
+        `csr_ucause,
+        `csr_utval,
+        `csr_uip,
+        `csr_sstatus,
+        `csr_sedeleg,
+        `csr_sideleg,
+        `csr_sie,
+        `csr_stvec,
+        `csr_scounteren,
+        `csr_sscratch,
+        `csr_sepc,
+        `csr_scause,
+        `csr_stval,
+        `csr_sip,
+        `csr_satp,
+        `csr_medeleg,
+        `csr_mideleg,
+        `csr_dcsr,
+        `csr_dpc,
+        `csr_dscratch:
+            get_csr_op_is_valid = 0;
+        `csr_cycle,
+        `csr_time,
+        `csr_instret,
+        `csr_cycleh,
+        `csr_timeh,
+        `csr_instreth,
+        `csr_mvendorid,
+        `csr_marchid,
+        `csr_mimpid,
+        `csr_mhartid:
+            get_csr_op_is_valid = ~csr_writes;
+        `csr_misa,
+        `csr_mstatus,
+        `csr_mie,
+        `csr_mtvec,
+        `csr_mscratch,
+        `csr_mepc,
+        `csr_mcause,
+        `csr_mip:
+            get_csr_op_is_valid = 1;
+        `csr_mcounteren,
+        `csr_mtval,
+        `csr_mcycle,
+        `csr_minstret,
+        `csr_mcycleh,
+        `csr_minstreth:
+            // TODO: CSRs not implemented yet
+            get_csr_op_is_valid = 0;
+        endcase
+    end
+    endfunction
+    
+    assign csr_op_is_valid = get_csr_op_is_valid(csr_number, csr_reads, csr_writes);
+
+    wire [63:0] cycle_counter = 0; // TODO: implement cycle_counter
+    wire [63:0] time_counter = 0; // TODO: implement time_counter
+    wire [63:0] instret_counter = 0; // TODO: implement instret_counter
+
+    always @(posedge clk) begin:main_block
+        if(reset) begin
+            reset_to_initial();
+            disable main_block;
+        end
+        case(fetch_output_state)
+        `fetch_output_state_empty: begin
+        end
+        `fetch_output_state_trap: begin
+            handle_trap();
+        end
+        `fetch_output_state_valid: begin:valid
+            if((fetch_action == `fetch_action_error_trap) | (fetch_action == `fetch_action_noerror_trap)) begin
+                handle_trap();
+            end
+            else if((decode_action & `decode_action_load) != 0) begin
+                if(~memory_interface_rw_wait)
+                    write_register(decoder_rd, loaded_value);
+            end
+            else if((decode_action & `decode_action_op_op_imm) != 0) begin
+                write_register(decoder_rd, alu_result);
+            end
+            else if((decode_action & `decode_action_lui_auipc) != 0) begin
+                write_register(decoder_rd, lui_auipc_result);
+            end
+            else if((decode_action & (`decode_action_jal | `decode_action_jalr)) != 0) begin
+                write_register(decoder_rd, fetch_output_pc + 4);
+            end
+            else if((decode_action & `decode_action_csr) != 0) begin:csr
+                reg [31:0] csr_output_value;
+                reg [31:0] csr_written_value;
+                csr_output_value = 32'hXXXXXXXX;
+                csr_written_value = 32'hXXXXXXXX;
+                case(csr_number)
+                `csr_cycle: begin
+                    csr_output_value = cycle_counter[31:0];
+                end
+                `csr_time: begin
+                    csr_output_value = time_counter[31:0];
+                end
+                `csr_instret: begin
+                    csr_output_value = instret_counter[31:0];
+                end
+                `csr_cycleh: begin
+                    csr_output_value = cycle_counter[63:32];
+                end
+                `csr_timeh: begin
+                    csr_output_value = time_counter[63:32];
+                end
+                `csr_instreth: begin
+                    csr_output_value = instret_counter[63:32];
+                end
+                `csr_mvendorid: begin
+                    csr_output_value = mvendorid;
+                end
+                `csr_marchid: begin
+                    csr_output_value = marchid;
+                end
+                `csr_mimpid: begin
+                    csr_output_value = mimpid;
+                end
+                `csr_mhartid: begin
+                    csr_output_value = mhartid;
+                end
+                `csr_misa: begin
+                    csr_output_value = misa;
+                end
+                `csr_mstatus: begin
+                    csr_output_value = make_mstatus(mstatus_tsr,
+                                                    mstatus_tw,
+                                                    mstatus_tvm,
+                                                    mstatus_mxr,
+                                                    mstatus_sum,
+                                                    mstatus_mprv,
+                                                    mstatus_xs,
+                                                    mstatus_fs,
+                                                    mstatus_mpp,
+                                                    mstatus_spp,
+                                                    mstatus_mpie,
+                                                    mstatus_spie,
+                                                    mstatus_upie,
+                                                    mstatus_mie,
+                                                    mstatus_sie,
+                                                    mstatus_uie);
+                    csr_written_value = evaluate_csr_funct3_operation(decoder_funct3, csr_output_value, csr_input_value);
+                    if(csr_writes) begin
+                        mstatus_mpie = csr_written_value[7];
+                        mstatus_mie = csr_written_value[3];
+                    end
+                end
+                `csr_mie: begin
+                    csr_output_value = 0;
+                    csr_output_value[11] = mie_meie;
+                    csr_output_value[9] = mie_seie;
+                    csr_output_value[8] = mie_ueie;
+                    csr_output_value[7] = mie_mtie;
+                    csr_output_value[5] = mie_stie;
+                    csr_output_value[4] = mie_utie;
+                    csr_output_value[3] = mie_msie;
+                    csr_output_value[1] = mie_ssie;
+                    csr_output_value[0] = mie_usie;
+                    csr_written_value = evaluate_csr_funct3_operation(decoder_funct3, csr_output_value, csr_input_value);
+                    if(csr_writes) begin
+                        mie_meie = csr_written_value[11];
+                        mie_mtie = csr_written_value[7];
+                        mie_msie = csr_written_value[3];
+                    end
+                end
+                `csr_mtvec: begin
+                    csr_output_value = mtvec;
+                end
+                `csr_mscratch: begin
+                    csr_output_value = mscratch;
+                    csr_written_value = evaluate_csr_funct3_operation(decoder_funct3, csr_output_value, csr_input_value);
+                    if(csr_writes)
+                        mscratch = csr_written_value;
+                end
+                `csr_mepc: begin
+                    csr_output_value = mepc;
+                    csr_written_value = evaluate_csr_funct3_operation(decoder_funct3, csr_output_value, csr_input_value);
+                    if(csr_writes)
+                        mepc = csr_written_value;
+                end
+                `csr_mcause: begin
+                    csr_output_value = mcause;
+                    csr_written_value = evaluate_csr_funct3_operation(decoder_funct3, csr_output_value, csr_input_value);
+                    if(csr_writes)
+                        mcause = csr_written_value;
+                end
+                `csr_mip: begin
+                    csr_output_value = 0;
+                    csr_output_value[11] = mip_meip;
+                    csr_output_value[9] = mip_seip;
+                    csr_output_value[8] = mip_ueip;
+                    csr_output_value[7] = mip_mtip;
+                    csr_output_value[5] = mip_stip;
+                    csr_output_value[4] = mip_utip;
+                    csr_output_value[3] = mip_msip;
+                    csr_output_value[1] = mip_ssip;
+                    csr_output_value[0] = mip_usip;
+                end
+                endcase
+                if(csr_reads)
+                    write_register(decoder_rd, csr_output_value);
+            end
+            else if((decode_action & (`decode_action_fence | `decode_action_fence_i | `decode_action_store | `decode_action_branch)) != 0) begin
+                // do nothing
+            end
+        end
+        endcase
+    end
+
+endmodule
diff --git a/cpu.vh b/cpu.vh
new file mode 100644 (file)
index 0000000..881d6b3
--- /dev/null
+++ b/cpu.vh
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`ifndef cpu_vh_
+`define cpu_vh_
+
+`define fetch_action [2:0]
+
+`define fetch_action_default 3'h0
+`define fetch_action_fence 3'h1
+`define fetch_action_jump 3'h2
+`define fetch_action_wait 3'h3
+`define fetch_action_error_trap 3'h4
+`define fetch_action_noerror_trap 3'h5
+`define fetch_action_ack_trap 3'h6
+
+`define fetch_output_state [1:0]
+
+`define fetch_output_state_empty 2'h0
+`define fetch_output_state_valid 2'h1
+`define fetch_output_state_trap 2'h2
+
+`define decode_action [11:0]
+
+`define decode_action_trap_illegal_instruction 'h1
+`define decode_action_load 'h2
+`define decode_action_fence 'h4
+`define decode_action_fence_i 'h8
+`define decode_action_op_op_imm 'h10
+`define decode_action_lui_auipc 'h20
+`define decode_action_store 'h40
+`define decode_action_branch 'h80
+`define decode_action_jalr 'h100
+`define decode_action_jal 'h200
+`define decode_action_trap_ecall_ebreak 'h400
+`define decode_action_csr 'h800
+
+`endif
+
diff --git a/cpu_alu.v b/cpu_alu.v
new file mode 100644 (file)
index 0000000..801401a
--- /dev/null
+++ b/cpu_alu.v
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+`include "riscv.vh"
+
+module cpu_alu(
+    input [6:0] funct7,
+    input [2:0] funct3,
+    input [6:0] opcode,
+    input [31:0] a,
+    input [31:0] b,
+    output [31:0] result
+    );
+    
+    wire is_sub = funct7[5] & opcode[5];
+    wire [31:0] add_sub_result = a + (is_sub ? ~b : b) + is_sub;
+    wire [31:0] shift_left_result = a << b[4:0];
+    wire [31:0] shift_right_result = funct7[5] ? $unsigned($signed(a) >>> b[4:0]) : a >> b[4:0];
+    wire [31:0] xor_result = a ^ b;
+    wire [31:0] or_result = a | b;
+    wire [31:0] and_result = a & b;
+    wire [31:0] lt_arg_flip = {~funct3[0], 31'b0};
+    wire [31:0] lt_result = ((a ^ lt_arg_flip) < (b ^ lt_arg_flip)) ? 32'b1 : 32'b0;
+    
+    function [31:0] mux8(
+        input [2:0] select,
+        input [31:0] v0,
+        input [31:0] v1,
+        input [31:0] v2,
+        input [31:0] v3,
+        input [31:0] v4,
+        input [31:0] v5,
+        input [31:0] v6,
+        input [31:0] v7);
+        begin
+            case(select)
+            0: mux8 = v0;
+            1: mux8 = v1;
+            2: mux8 = v2;
+            3: mux8 = v3;
+            4: mux8 = v4;
+            5: mux8 = v5;
+            6: mux8 = v6;
+            7: mux8 = v7;
+            default: mux8 = 32'hXXXXXXXX;
+            endcase
+        end
+    endfunction
+    
+    assign result = mux8(funct3,
+                         add_sub_result,
+                         shift_left_result,
+                         lt_result,
+                         lt_result,
+                         xor_result,
+                         shift_right_result,
+                         or_result,
+                         and_result);
+    
+endmodule
diff --git a/cpu_decoder.v b/cpu_decoder.v
new file mode 100644 (file)
index 0000000..ffd943b
--- /dev/null
@@ -0,0 +1,254 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+`include "riscv.vh"
+`include "cpu.vh"
+
+module cpu_decoder(
+    input [31:0] instruction,
+    output [6:0] funct7,
+    output [2:0] funct3,
+    output [4:0] rd,
+    output [4:0] rs1,
+    output [4:0] rs2,
+    output [31:0] immediate,
+    output [6:0] opcode,
+    output `decode_action decode_action
+    );
+    
+    assign funct7 = instruction[31:25];
+    assign funct3 = instruction[14:12];
+    assign rd = instruction[11:7];
+    assign rs1 = instruction[19:15];
+    assign rs2 = instruction[24:20];
+    assign opcode = instruction[6:0];
+    
+    function [31:0] calculate_immediate(input [31:0] instruction, input [6:0] opcode);
+    begin
+        case(opcode)
+        `opcode_amo,
+        `opcode_op,
+        `opcode_op_32,
+        `opcode_op_fp:
+            // R-type: no immediate
+            calculate_immediate = 32'hXXXXXXXX;
+        `opcode_load,
+        `opcode_load_fp,
+        `opcode_misc_mem,
+        `opcode_op_imm,
+        `opcode_op_imm_32,
+        `opcode_jalr,
+        `opcode_system:
+            // I-type
+            calculate_immediate = {{20{instruction[31]}}, instruction[31:20]};
+        `opcode_store,
+        `opcode_store_fp:
+            // S-type
+            calculate_immediate = {{21{instruction[31]}}, instruction[30:25], instruction[11:7]};
+        `opcode_branch:
+            // B-type
+            calculate_immediate = {{20{instruction[31]}}, instruction[7], instruction[30:25], instruction[11:8], 1'b0};
+        `opcode_auipc,
+        `opcode_lui:
+            // U-type
+            calculate_immediate = {instruction[31:12], 12'b0};
+        `opcode_jal:
+            // J-type
+            calculate_immediate = {{12{instruction[31]}}, instruction[19:12], instruction[20], instruction[30:25], instruction[24:21], 1'b0};
+        `opcode_madd,
+        `opcode_msub,
+        `opcode_nmsub,
+        `opcode_nmadd:
+            // R4-type: no immediate
+            calculate_immediate = 32'hXXXXXXXX;
+        `opcode_custom_0,
+        `opcode_48b_escape_0,
+        `opcode_custom_1,
+        `opcode_64b_escape,
+        `opcode_reserved_10101,
+        `opcode_rv128_0,
+        `opcode_48b_escape_1,
+        `opcode_reserved_11010,
+        `opcode_reserved_11101,
+        `opcode_rv128_1,
+        `opcode_80b_escape:
+            // unknown
+            calculate_immediate = 32'hXXXXXXXX;
+        default:
+            calculate_immediate = 32'hXXXXXXXX;
+        endcase
+    end
+    endfunction
+    
+    assign immediate = calculate_immediate(instruction, opcode);
+    
+    function `decode_action calculate_action(
+        input [6:0] funct7,
+        input [2:0] funct3,
+        input [4:0] rd,
+        input [4:0] rs1,
+        input [4:0] rs2,
+        input [31:0] immediate,
+        input [6:0] opcode);
+    begin
+        case(opcode)
+        `opcode_load: begin
+            case(funct3)
+            `funct3_lb,
+            `funct3_lbu,
+            `funct3_lh,
+            `funct3_lhu,
+            `funct3_lw:
+                calculate_action = `decode_action_load;
+            default:
+                calculate_action = `decode_action_trap_illegal_instruction;
+            endcase
+        end
+        `opcode_misc_mem: begin
+            if(funct3 == `funct3_fence) begin
+                if((immediate[11:8] == 0) & (rs1 == 0) & (rd == 0))
+                    calculate_action = `decode_action_fence;
+                else
+                    calculate_action = `decode_action_trap_illegal_instruction;
+            end
+            else if(funct3 == `funct3_fence_i) begin
+                if((immediate[11:0] == 0) & (rs1 == 0) & (rd == 0))
+                    calculate_action = `decode_action_fence_i;
+                else
+                    calculate_action = `decode_action_trap_illegal_instruction;
+            end
+            else
+            begin
+                calculate_action = `decode_action_trap_illegal_instruction;
+            end
+        end
+        `opcode_op_imm,
+        `opcode_op: begin
+            if(funct3 == `funct3_slli) begin
+                if(funct7 == 0)
+                    calculate_action = `decode_action_op_op_imm;
+                else
+                    calculate_action = `decode_action_trap_illegal_instruction;
+            end
+            else if(funct3 == `funct3_srli_srai) begin
+                if(funct7 == 0 || funct7 == 7'h20)
+                    calculate_action = `decode_action_op_op_imm;
+                else
+                    calculate_action = `decode_action_trap_illegal_instruction;
+            end
+            else begin
+                calculate_action = `decode_action_op_op_imm;
+            end
+        end
+        `opcode_lui,
+        `opcode_auipc: begin
+            calculate_action = `decode_action_lui_auipc;
+        end
+        `opcode_store: begin
+            case(funct3)
+            `funct3_sb,
+            `funct3_sh,
+            `funct3_sw:
+                calculate_action = `decode_action_store;
+            default:
+                calculate_action = `decode_action_trap_illegal_instruction;
+            endcase
+        end
+        `opcode_branch: begin
+            case(funct3)
+            `funct3_beq,
+            `funct3_bne,
+            `funct3_blt,
+            `funct3_bge,
+            `funct3_bltu,
+            `funct3_bgeu:
+                calculate_action = `decode_action_branch;
+            default:
+                calculate_action = `decode_action_trap_illegal_instruction;
+            endcase
+        end
+        `opcode_jalr: begin
+            if(funct3 == `funct3_jalr)
+                calculate_action = `decode_action_jalr;
+            else
+                calculate_action = `decode_action_trap_illegal_instruction;
+        end
+        `opcode_jal: begin
+            calculate_action = `decode_action_jal;
+        end
+        `opcode_system: begin
+            case(funct3)
+            `funct3_ecall_ebreak:
+                if((rs1 != 0) | (rd != 0) | ((immediate & ~32'b1) != 0))
+                    calculate_action = `decode_action_trap_illegal_instruction;
+                else
+                    calculate_action = `decode_action_trap_ecall_ebreak;
+            `funct3_csrrw,
+            `funct3_csrrs,
+            `funct3_csrrc,
+            `funct3_csrrwi,
+            `funct3_csrrsi,
+            `funct3_csrrci:
+                calculate_action = `decode_action_csr;
+            default:
+                calculate_action = `decode_action_trap_illegal_instruction;
+            endcase
+        end
+        `opcode_load_fp,
+        `opcode_custom_0,
+        `opcode_op_imm_32,
+        `opcode_48b_escape_0,
+        `opcode_store_fp,
+        `opcode_custom_1,
+        `opcode_amo,
+        `opcode_op_32,
+        `opcode_64b_escape,
+        `opcode_madd,
+        `opcode_msub,
+        `opcode_nmsub,
+        `opcode_nmadd,
+        `opcode_op_fp,
+        `opcode_reserved_10101,
+        `opcode_rv128_0,
+        `opcode_48b_escape_1,
+        `opcode_reserved_11010,
+        `opcode_reserved_11101,
+        `opcode_rv128_1,
+        `opcode_80b_escape: begin
+            calculate_action = `decode_action_trap_illegal_instruction;
+        end
+        default:
+            calculate_action = `decode_action_trap_illegal_instruction;
+        endcase
+    end
+    endfunction
+    
+    assign decode_action = calculate_action(funct7,
+                                            funct3,
+                                            rd,
+                                            rs1,
+                                            rs2,
+                                            immediate,
+                                            opcode);
+    
+endmodule
diff --git a/cpu_fetch_stage.v b/cpu_fetch_stage.v
new file mode 100644 (file)
index 0000000..0e1ed59
--- /dev/null
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+`include "riscv.vh"
+`include "cpu.vh"
+
+module cpu_fetch_stage(
+    input clk,
+    input reset,
+    output [31:2] memory_interface_fetch_address,
+    input [31:0] memory_interface_fetch_data,
+    input memory_interface_fetch_valid,
+    input `fetch_action fetch_action,
+    input [31:0] target_pc,
+    output reg [31:0] output_pc,
+    output [31:0] output_instruction,
+    output reg `fetch_output_state output_state
+    );
+    
+    parameter reset_vector = 32'hXXXXXXXX;
+    parameter mtvec = 32'hXXXXXXXX;
+
+    reg [31:0] fetch_pc = reset_vector;
+    
+    always @(posedge clk or posedge reset) output_pc <= reset ? reset_vector : ((fetch_action == `fetch_action_wait) ? output_pc : fetch_pc);
+    
+    assign memory_interface_fetch_address = fetch_pc[31:2];
+
+    initial output_pc <= reset_vector;
+    initial output_state <= `fetch_output_state_empty;
+    
+    reg [31:0] delayed_instruction = 0;
+    reg delayed_instruction_valid = 0;
+    
+    always @(posedge clk or posedge reset) delayed_instruction <= reset ? 0 : output_instruction;
+    
+    assign output_instruction = delayed_instruction_valid ? delayed_instruction : memory_interface_fetch_data;
+    
+    always @(posedge clk or posedge reset) begin
+        if(reset)
+            delayed_instruction_valid <= 0;
+        else
+            delayed_instruction_valid <= fetch_action == `fetch_action_wait;
+    end
+    
+    always @(posedge clk or posedge reset) begin
+        if(reset) begin
+            fetch_pc <= reset_vector;
+            output_state <= `fetch_output_state_empty;
+        end
+        else begin
+            case(fetch_action)
+            `fetch_action_default,
+            `fetch_action_ack_trap: begin
+                if(memory_interface_fetch_valid) begin
+                    fetch_pc <= fetch_pc + 4;
+                    output_state <= `fetch_output_state_valid;
+                end
+                else begin
+                    fetch_pc <= mtvec;
+                    output_state <= `fetch_output_state_trap;
+                end
+            end
+            `fetch_action_fence: begin
+                fetch_pc <= output_pc + 4;
+                output_state <= `fetch_output_state_empty;
+            end
+            `fetch_action_jump: begin
+                fetch_pc <= target_pc;
+                output_state <= `fetch_output_state_empty;
+            end
+            `fetch_action_error_trap,
+            `fetch_action_noerror_trap: begin
+                fetch_pc <= mtvec;
+                output_state <= `fetch_output_state_empty;
+            end
+            `fetch_action_wait: begin
+                fetch_pc <= fetch_pc;
+                output_state <= `fetch_output_state_valid;
+            end
+            endcase
+        end
+    end
+endmodule
diff --git a/cpu_memory_interface.v b/cpu_memory_interface.v
new file mode 100644 (file)
index 0000000..b299ec5
--- /dev/null
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 1ps
+module cpu_memory_interface(
+    input clk,
+    input reset,
+    input [31:2] fetch_address,
+    output [31:0] fetch_data,
+    output fetch_valid,
+    input [31:2] rw_address,
+    input [3:0] rw_byte_mask,
+    input rw_read_not_write,
+    input rw_active,
+    input [31:0] rw_data_in,
+    output [31:0] rw_data_out,
+    output rw_address_valid,
+    output rw_wait,
+    output reg tty_write,
+    output reg [7:0] tty_write_data,
+    input tty_write_busy,
+    input switch_2,
+    input switch_3,
+    output led_1,
+    output led_3
+    );
+
+    parameter ram_size = 32'hXXXXXXXX;
+    parameter ram_start = 32'hXXXXXXXX;
+    parameter tty_location = 32'h8000_0000;
+    parameter gpio_location = 32'h8000_0010;
+    
+    wire ram_a_write_enable = ~reset & ~ignore_after_delay & rw_active & rw_address_in_mem_space & ~rw_read_not_write;
+    
+    wire [31:0] ram_a_ram_address = rw_address_in_mem_space ? rw_address - ram_start / 4 : 0;
+    wire [3:0] ram_a_write_enable_bytes = {4{ram_a_write_enable}} & rw_byte_mask;
+    wire [31:0] ram_a_write_input = rw_data_in;
+    wire [31:0] ram_a_read_output;
+    wire [31:0] ram_b_ram_address = fetch_address_valid ? fetch_address - ram_start / 4 : 0;
+    wire [31:0] ram_b_read_output;
+    
+    block_memory ram(
+        .clk(clk),
+        .a_ram_address(ram_a_ram_address),
+        .a_write_enable(ram_a_write_enable_bytes),
+        .a_write_input(ram_a_write_input),
+        .a_read_output(ram_a_read_output),
+        .b_ram_address(ram_b_ram_address),
+        .b_read_output(ram_b_read_output)
+        );
+    
+    wire fetch_address_valid = (fetch_address >= ram_start / 4) & (fetch_address < (ram_start + ram_size) / 4);
+    wire rw_address_is_tty = (rw_address == tty_location / 4) & (rw_read_not_write | rw_byte_mask == 4'h1);
+    wire rw_address_is_gpio = rw_address == gpio_location / 4;
+    wire rw_address_in_io_space = rw_address_is_tty | rw_address_is_gpio;
+    wire rw_address_in_mem_space = (rw_address >= ram_start / 4) & (rw_address < (ram_start + ram_size) / 4);
+    assign rw_address_valid = rw_address_in_mem_space | rw_address_in_io_space;
+    
+    reg delay_done = 0;
+    
+    assign fetch_data = ram_b_read_output;
+
+    assign fetch_valid = ~reset & fetch_address_valid;
+    
+    assign rw_wait = (rw_address_in_mem_space
+                     ? (rw_read_not_write 
+                        ? ~delay_done
+                        : 1'b0)
+                     : ~delay_done) | reset;
+                     
+    reg ignore_after_delay = 0;
+    
+    reg [31:0] io_read_output_register;
+    reg last_read_was_ram;
+    
+    assign rw_data_out = last_read_was_ram ? ram_a_read_output : io_read_output_register;
+    
+    reg [7:0] gpio_input_sync_first = 0;
+    reg [7:0] gpio_input = 0;
+    always @(posedge clk) gpio_input_sync_first <= {5'b0, ~switch_3, ~switch_2, 1'b0};
+    always @(posedge clk) gpio_input <= gpio_input_sync_first;
+    reg [7:0] gpio_output = 0;
+    assign led_1 = ~gpio_output[0];
+    assign led_3 = ~gpio_output[2];
+    
+    always @(posedge clk or posedge reset) begin
+        if(reset) begin
+            delay_done <= 0;
+            tty_write <= 0;
+            ignore_after_delay <= 0;
+            io_read_output_register <= 'hXXXXXXXX;
+            last_read_was_ram <= 1'hX;
+            gpio_output <= 0;
+        end
+        else begin
+            delay_done <= 0;
+            tty_write <= 0;
+            if(ignore_after_delay) begin
+                ignore_after_delay <= 0;
+            end
+            else if(rw_active & rw_address_in_mem_space) begin
+                if(rw_read_not_write) begin
+                    delay_done <= 1;
+                    ignore_after_delay <= 1;
+                    last_read_was_ram <= 1;
+                end
+                else begin
+                    last_read_was_ram <= 1;
+                end
+            end
+            else if(rw_active & rw_address_in_io_space) begin
+                if(rw_address_is_tty) begin
+                    if(rw_read_not_write) begin
+                        last_read_was_ram <= 0;
+                        io_read_output_register <= 0;
+                        delay_done <= 1;
+                        ignore_after_delay <= 1;
+                    end
+                    else begin
+                        if(tty_write_busy) begin
+                            delay_done <= 0;
+                        end
+                        else begin
+                            tty_write <= 1;
+                            tty_write_data <= rw_data_in[7:0];
+                            delay_done <= 1;
+                            ignore_after_delay <= 1;
+                        end
+                        last_read_was_ram <= 0;
+                        io_read_output_register <= 'hXXXXXXXX;
+                    end
+                end
+                else if(rw_address_is_gpio) begin
+                    if(rw_read_not_write) begin
+                        last_read_was_ram <= 0;
+                        io_read_output_register <= {16'b0, gpio_input, gpio_output};
+                        delay_done <= 1;
+                        ignore_after_delay <= 1;
+                    end
+                    else begin
+                        if(rw_byte_mask[0])
+                            gpio_output <= rw_data_in[7:0];
+                        delay_done <= 1;
+                        ignore_after_delay <= 1;
+                        last_read_was_ram <= 0;
+                        io_read_output_register <= 'hXXXXXXXX;
+                    end
+                end
+                else begin
+                    //TODO finish implementing I/O
+                    last_read_was_ram <= 0;
+                    io_read_output_register <= 'hXXXXXXXX;
+                end
+            end
+            else begin
+                last_read_was_ram <= 0;
+                io_read_output_register <= 'hXXXXXXXX;
+            end
+        end
+    end
+
+endmodule
diff --git a/font8x8.hex b/font8x8.hex
new file mode 100644 (file)
index 0000000..401e7b1
--- /dev/null
@@ -0,0 +1,256 @@
+7F 41 61 51 4B 45 7F 00
+7E 81 A5 81 BD 99 81 7E
+7E FF DB FF C3 E7 FF 7E
+36 7F 7F 7F 3E 1C 08 00
+08 1C 3E 7F 3E 1C 08 00
+1C 3E 1C 7F 7F 3E 1C 3E
+08 08 1C 3E 7F 3E 1C 3E
+00 00 18 3C 3C 18 00 00
+FF FF E7 C3 C3 E7 FF FF
+00 3C 66 42 42 66 3C 00
+FF C3 99 BD BD 99 C3 FF
+F0 E0 F0 BE 33 33 33 1E
+3C 66 66 66 3C 18 7E 18
+FC CC FC 0C 0C 0E 0F 07
+FE C6 FE C6 C6 E6 67 03
+99 5A 3C E7 E7 3C 5A 99
+01 07 1F 7F 1F 07 01 00
+40 70 7C 7F 7C 70 40 00
+18 3C 7E 18 18 7E 3C 18
+66 66 66 66 66 00 66 00
+FE DB DB DE D8 D8 D8 00
+7C C6 1C 36 36 1C 33 1E
+00 00 00 00 7E 7E 7E 00
+18 3C 7E 18 7E 3C 18 FF
+18 3C 7E 18 18 18 18 00
+18 18 18 18 7E 3C 18 00
+00 18 30 7F 30 18 00 00
+00 0C 06 7F 06 0C 00 00
+00 00 03 03 03 7F 00 00
+00 24 66 FF 66 24 00 00
+00 18 3C 7E FF FF 00 00
+00 FF FF 7E 3C 18 00 00
+00 00 00 00 00 00 00 00
+0C 1E 1E 0C 0C 00 0C 00
+36 36 36 00 00 00 00 00
+36 36 7F 36 7F 36 36 00
+0C 3E 03 1E 30 1F 0C 00
+00 63 33 18 0C 66 63 00
+1C 36 1C 6E 3B 33 6E 00
+06 06 03 00 00 00 00 00
+18 0C 06 06 06 0C 18 00
+06 0C 18 18 18 0C 06 00
+00 66 3C FF 3C 66 00 00
+00 0C 0C 3F 0C 0C 00 00
+00 00 00 00 00 0C 0C 06
+00 00 00 3F 00 00 00 00
+00 00 00 00 00 0C 0C 00
+60 30 18 0C 06 03 01 00
+3E 63 73 7B 6F 67 3E 00
+0C 0E 0C 0C 0C 0C 3F 00
+1E 33 30 1C 06 33 3F 00
+1E 33 30 1C 30 33 1E 00
+38 3C 36 33 7F 30 78 00
+3F 03 1F 30 30 33 1E 00
+1C 06 03 1F 33 33 1E 00
+3F 33 30 18 0C 0C 0C 00
+1E 33 33 1E 33 33 1E 00
+1E 33 33 3E 30 18 0E 00
+00 0C 0C 00 00 0C 0C 00
+00 0C 0C 00 00 0C 0C 06
+18 0C 06 03 06 0C 18 00
+00 00 3F 00 00 3F 00 00
+06 0C 18 30 18 0C 06 00
+1E 33 30 18 0C 00 0C 00
+3E 63 7B 7B 7B 03 1E 00
+0C 1E 33 33 3F 33 33 00
+3F 66 66 3E 66 66 3F 00
+3C 66 03 03 03 66 3C 00
+1F 36 66 66 66 36 1F 00
+7F 46 16 1E 16 46 7F 00
+7F 46 16 1E 16 06 0F 00
+3C 66 03 03 73 66 7C 00
+33 33 33 3F 33 33 33 00
+1E 0C 0C 0C 0C 0C 1E 00
+78 30 30 30 33 33 1E 00
+67 66 36 1E 36 66 67 00
+0F 06 06 06 46 66 7F 00
+63 77 7F 7F 6B 63 63 00
+63 67 6F 7B 73 63 63 00
+1C 36 63 63 63 36 1C 00
+3F 66 66 3E 06 06 0F 00
+1E 33 33 33 3B 1E 38 00
+3F 66 66 3E 36 66 67 00
+1E 33 07 0E 38 33 1E 00
+3F 2D 0C 0C 0C 0C 1E 00
+33 33 33 33 33 33 3F 00
+33 33 33 33 33 1E 0C 00
+63 63 63 6B 7F 77 63 00
+63 63 36 1C 1C 36 63 00
+33 33 33 1E 0C 0C 1E 00
+7F 63 31 18 4C 66 7F 00
+1E 06 06 06 06 06 1E 00
+03 06 0C 18 30 60 40 00
+1E 18 18 18 18 18 1E 00
+08 1C 36 63 00 00 00 00
+00 00 00 00 00 00 00 FF
+0C 0C 18 00 00 00 00 00
+00 00 1E 30 3E 33 6E 00
+07 06 06 3E 66 66 3B 00
+00 00 1E 33 03 33 1E 00
+38 30 30 3E 33 33 6E 00
+00 00 1E 33 3F 03 1E 00
+1C 36 06 0F 06 06 0F 00
+00 00 6E 33 33 3E 30 1F
+07 06 36 6E 66 66 67 00
+0C 00 0E 0C 0C 0C 1E 00
+30 00 30 30 30 33 33 1E
+07 06 66 36 1E 36 67 00
+0E 0C 0C 0C 0C 0C 1E 00
+00 00 33 7F 7F 6B 63 00
+00 00 1F 33 33 33 33 00
+00 00 1E 33 33 33 1E 00
+00 00 3B 66 66 3E 06 0F
+00 00 6E 33 33 3E 30 78
+00 00 3B 6E 66 06 0F 00
+00 00 3E 03 1E 30 1F 00
+08 0C 3E 0C 0C 2C 18 00
+00 00 33 33 33 33 6E 00
+00 00 33 33 33 1E 0C 00
+00 00 63 6B 7F 7F 36 00
+00 00 63 36 1C 36 63 00
+00 00 33 33 33 3E 30 1F
+00 00 3F 19 0C 26 3F 00
+38 0C 0C 07 0C 0C 38 00
+18 18 18 00 18 18 18 00
+07 0C 0C 38 0C 0C 07 00
+6E 3B 00 00 00 00 00 00
+00 08 1C 36 63 63 7F 00
+1E 33 03 33 1E 18 30 1E
+00 33 00 33 33 33 7E 00
+38 00 1E 33 3F 03 1E 00
+7E C3 3C 60 7C 66 FC 00
+33 00 1E 30 3E 33 7E 00
+07 00 1E 30 3E 33 7E 00
+0C 0C 1E 30 3E 33 7E 00
+00 00 1E 03 03 1E 30 1C
+7E C3 3C 66 7E 06 3C 00
+33 00 1E 33 3F 03 1E 00
+07 00 1E 33 3F 03 1E 00
+33 00 0E 0C 0C 0C 1E 00
+3E 63 1C 18 18 18 3C 00
+07 00 0E 0C 0C 0C 1E 00
+63 1C 36 63 7F 63 63 00
+0C 0C 00 1E 33 3F 33 00
+38 00 3F 06 1E 06 3F 00
+00 00 FE 30 FE 33 FE 00
+7C 36 33 7F 33 33 73 00
+1E 33 00 1E 33 33 1E 00
+00 33 00 1E 33 33 1E 00
+00 07 00 1E 33 33 1E 00
+1E 33 00 33 33 33 7E 00
+00 07 00 33 33 33 7E 00
+00 33 00 33 33 3E 30 1F
+C3 18 3C 66 66 3C 18 00
+33 00 33 33 33 33 1E 00
+18 18 7E 03 03 7E 18 18
+1C 36 26 0F 06 67 3F 00
+33 33 1E 3F 0C 3F 0C 0C
+1F 33 33 5F 63 F3 63 E3
+70 D8 18 3C 18 18 1B 0E
+38 00 1E 30 3E 33 7E 00
+1C 00 0E 0C 0C 0C 1E 00
+00 38 00 1E 33 33 1E 00
+00 38 00 33 33 33 7E 00
+00 1F 00 1F 33 33 33 00
+3F 00 33 37 3F 3B 33 00
+3C 36 36 7C 00 7E 00 00
+1C 36 36 1C 00 3E 00 00
+0C 00 0C 06 03 33 1E 00
+00 00 00 3F 03 03 00 00
+00 00 00 3F 30 30 00 00
+C3 63 33 7B CC 66 33 F0
+C3 63 33 DB EC F6 F3 C0
+18 18 00 18 18 18 18 00
+00 CC 66 33 66 CC 00 00
+00 33 66 CC 66 33 00 00
+44 11 44 11 44 11 44 11
+AA 55 AA 55 AA 55 AA 55
+DB EE DB 77 DB EE DB 77
+18 18 18 18 18 18 18 18
+18 18 18 18 1F 18 18 18
+18 18 1F 18 1F 18 18 18
+6C 6C 6C 6C 6F 6C 6C 6C
+00 00 00 00 7F 6C 6C 6C
+00 00 1F 18 1F 18 18 18
+6C 6C 6F 60 6F 6C 6C 6C
+6C 6C 6C 6C 6C 6C 6C 6C
+00 00 7F 60 6F 6C 6C 6C
+6C 6C 6F 60 7F 00 00 00
+6C 6C 6C 6C 7F 00 00 00
+18 18 1F 18 1F 00 00 00
+00 00 00 00 1F 18 18 18
+18 18 18 18 F8 00 00 00
+18 18 18 18 FF 00 00 00
+00 00 00 00 FF 18 18 18
+18 18 18 18 F8 18 18 18
+00 00 00 00 FF 00 00 00
+18 18 18 18 FF 18 18 18
+18 18 F8 18 F8 18 18 18
+6C 6C 6C 6C EC 6C 6C 6C
+6C 6C EC 0C FC 00 00 00
+00 00 FC 0C EC 6C 6C 6C
+6C 6C EF 00 FF 00 00 00
+00 00 FF 00 EF 6C 6C 6C
+6C 6C EC 0C EC 6C 6C 6C
+00 00 FF 00 FF 00 00 00
+6C 6C EF 00 EF 6C 6C 6C
+18 18 FF 00 FF 00 00 00
+6C 6C 6C 6C FF 00 00 00
+00 00 FF 00 FF 18 18 18
+00 00 00 00 FF 6C 6C 6C
+6C 6C 6C 6C FC 00 00 00
+18 18 F8 18 F8 00 00 00
+00 00 F8 18 F8 18 18 18
+00 00 00 00 FC 6C 6C 6C
+6C 6C 6C 6C FF 6C 6C 6C
+18 18 FF 18 FF 18 18 18
+18 18 18 18 1F 00 00 00
+00 00 00 00 F8 18 18 18
+FF FF FF FF FF FF FF FF
+00 00 00 00 FF FF FF FF
+0F 0F 0F 0F 0F 0F 0F 0F
+F0 F0 F0 F0 F0 F0 F0 F0
+FF FF FF FF 00 00 00 00
+00 00 6E 3B 13 3B 6E 00
+00 1E 33 1F 33 1F 03 03
+00 3F 33 03 03 03 03 00
+00 7F 36 36 36 36 36 00
+3F 33 06 0C 06 33 3F 00
+00 00 7E 1B 1B 1B 0E 00
+00 66 66 66 66 3E 06 03
+00 6E 3B 18 18 18 18 00
+3F 0C 1E 33 33 1E 0C 3F
+1C 36 63 7F 63 36 1C 00
+1C 36 63 63 36 36 77 00
+38 0C 18 3E 33 33 1E 00
+00 00 7E DB DB 7E 00 00
+60 30 7E DB DB 7E 06 03
+1C 06 03 1F 03 06 1C 00
+1E 33 33 33 33 33 33 00
+00 3F 00 3F 00 3F 00 00
+0C 0C 3F 0C 0C 00 3F 00
+06 0C 18 0C 06 00 3F 00
+18 0C 06 0C 18 00 3F 00
+70 D8 D8 18 18 18 18 18
+18 18 18 18 18 1B 1B 0E
+0C 0C 00 3F 00 0C 0C 00
+00 6E 3B 00 6E 3B 00 00
+1C 36 36 1C 00 00 00 00
+00 00 00 18 18 00 00 00
+00 00 00 00 18 00 00 00
+F0 30 30 30 37 36 3C 38
+1E 36 36 36 36 00 00 00
+0E 18 0C 06 1E 00 00 00
+00 00 3C 3C 3C 3C 00 00
+7F 41 41 41 41 41 7F 00
diff --git a/main.bit b/main.bit
new file mode 100644 (file)
index 0000000..4e42e98
Binary files /dev/null and b/main.bit differ
diff --git a/main.ucf b/main.ucf
new file mode 100644 (file)
index 0000000..2eefb7d
--- /dev/null
+++ b/main.ucf
@@ -0,0 +1,94 @@
+NET "clk" LOC = A10;
+
+NET "vga_hsync" SLEW = FAST;
+NET "vga_vsync" SLEW = FAST;
+
+NET "vga_hsync" LOC = A14;
+NET "vga_vsync" LOC = B14;
+
+NET "vga_r[0]" SLEW = FAST;
+NET "vga_r[1]" SLEW = FAST;
+NET "vga_r[2]" SLEW = FAST;
+NET "vga_r[3]" SLEW = FAST;
+NET "vga_r[4]" SLEW = FAST;
+NET "vga_r[5]" SLEW = FAST;
+NET "vga_r[6]" SLEW = FAST;
+NET "vga_r[7]" SLEW = FAST;
+
+NET "vga_r[0]" LOC = R12;
+NET "vga_r[1]" LOC = T12;
+NET "vga_r[2]" LOC = T14;
+NET "vga_r[3]" LOC = T13;
+NET "vga_r[4]" LOC = T15;
+NET "vga_r[5]" LOC = R14;
+NET "vga_r[6]" LOC = R16;
+NET "vga_r[7]" LOC = R15;
+
+NET "vga_g[0]" SLEW = FAST;
+NET "vga_g[1]" SLEW = FAST;
+NET "vga_g[2]" SLEW = FAST;
+NET "vga_g[3]" SLEW = FAST;
+NET "vga_g[4]" SLEW = FAST;
+NET "vga_g[5]" SLEW = FAST;
+NET "vga_g[6]" SLEW = FAST;
+NET "vga_g[7]" SLEW = FAST;
+
+NET "vga_g[0]" LOC = P16;
+NET "vga_g[1]" LOC = P15;
+NET "vga_g[2]" LOC = L13;
+NET "vga_g[3]" LOC = L12;
+NET "vga_g[4]" LOC = M14;
+NET "vga_g[5]" LOC = M13;
+NET "vga_g[6]" LOC = N16;
+NET "vga_g[7]" LOC = N14;
+
+NET "vga_b[0]" SLEW = FAST;
+NET "vga_b[1]" SLEW = FAST;
+NET "vga_b[2]" SLEW = FAST;
+NET "vga_b[3]" SLEW = FAST;
+NET "vga_b[4]" SLEW = FAST;
+NET "vga_b[5]" SLEW = FAST;
+NET "vga_b[6]" SLEW = FAST;
+NET "vga_b[7]" SLEW = FAST;
+
+NET "vga_b[0]" LOC = M15;
+NET "vga_b[1]" LOC = K12;
+NET "vga_b[2]" LOC = K11;
+NET "vga_b[3]" LOC = L14;
+NET "vga_b[4]" LOC = L16;
+NET "vga_b[5]" LOC = K16;
+NET "vga_b[6]" LOC = K15;
+NET "vga_b[7]" LOC = J13;
+
+NET "vga_pixel_clock" LOC = K14;
+
+NET "vga_pixel_clock" SLEW = FAST;
+
+NET "vga_blank" LOC = M16;
+
+NET "vga_blank" SLEW = FAST;
+
+NET "clk" TNM_NET = "clk";
+TIMESPEC TS_clk = PERIOD "clk" 20 ns HIGH 50 %;
+
+INST "cpu1/memory_interface/ram/ram_0_byte0/Mram_ram" LOC = RAMB16_X0Y30;
+INST "cpu1/memory_interface/ram/ram_0_byte1/Mram_ram" LOC = RAMB16_X0Y22;
+INST "cpu1/memory_interface/ram/ram_0_byte2/Mram_ram" LOC = RAMB16_X1Y30;
+INST "cpu1/memory_interface/ram/ram_0_byte3/Mram_ram" LOC = RAMB16_X1Y22;
+INST "cpu1/memory_interface/ram/ram_1_byte0/Mram_ram" LOC = RAMB16_X0Y28;
+INST "cpu1/memory_interface/ram/ram_1_byte1/Mram_ram" LOC = RAMB16_X0Y20;
+INST "cpu1/memory_interface/ram/ram_1_byte2/Mram_ram" LOC = RAMB16_X1Y28;
+INST "cpu1/memory_interface/ram/ram_1_byte3/Mram_ram" LOC = RAMB16_X1Y20;
+INST "cpu1/memory_interface/ram/ram_2_byte0/Mram_ram" LOC = RAMB16_X0Y26;
+INST "cpu1/memory_interface/ram/ram_2_byte1/Mram_ram" LOC = RAMB16_X0Y18;
+INST "cpu1/memory_interface/ram/ram_2_byte2/Mram_ram" LOC = RAMB16_X1Y26;
+INST "cpu1/memory_interface/ram/ram_2_byte3/Mram_ram" LOC = RAMB16_X1Y18;
+INST "cpu1/memory_interface/ram/ram_3_byte0/Mram_ram" LOC = RAMB16_X0Y24;
+INST "cpu1/memory_interface/ram/ram_3_byte1/Mram_ram" LOC = RAMB16_X0Y16;
+INST "cpu1/memory_interface/ram/ram_3_byte2/Mram_ram" LOC = RAMB16_X1Y24;
+INST "cpu1/memory_interface/ram/ram_3_byte3/Mram_ram" LOC = RAMB16_X1Y16;
+
+NET "switch_2" LOC = T8;
+NET "switch_3" LOC = R7;
+NET "led_1" LOC = T9;
+NET "led_3" LOC = R9;
diff --git a/main.v b/main.v
new file mode 100644 (file)
index 0000000..3d66ba9
--- /dev/null
+++ b/main.v
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module main(
+    input clk,
+    output [7:0] vga_r,
+       output [7:0] vga_g,
+       output [7:0] vga_b,
+       output vga_hsync,
+       output vga_vsync,
+    output vga_blank,
+    output vga_pixel_clock,
+    input switch_2,
+    input switch_3,
+    output led_1,
+    output led_3
+    );
+    
+    wire tty_write;
+    wire [7:0] tty_write_data;
+    wire tty_write_busy;
+    reg reset = 1;
+    
+       vga vga1(
+        .clk(clk),
+        .vga_r(vga_r),
+        .vga_g(vga_g),
+        .vga_b(vga_b),
+        .vga_hsync(vga_hsync),
+        .vga_vsync(vga_vsync),
+        .vga_blank(vga_blank),
+        .vga_pixel_clock(vga_pixel_clock),
+        .tty_write(tty_write),
+        .tty_data(tty_write_data),
+        .tty_busy(tty_write_busy)
+        );
+    
+    cpu cpu1(
+        .clk(clk),
+        .reset(reset),
+        .tty_write(tty_write),
+        .tty_write_data(tty_write_data),
+        .tty_write_busy(tty_write_busy),
+        .switch_2(switch_2),
+        .switch_3(switch_3),
+        .led_1(led_1),
+        .led_3(led_3)
+        );
+    
+    reg [31:0] reset_counter = 256;
+    
+    always @(posedge clk)
+        if(reset_counter == 0)
+            reset <= 0;
+        else
+            reset_counter <= reset_counter - 1;
+
+endmodule
diff --git a/main_test.v b/main_test.v
new file mode 100644 (file)
index 0000000..404b101
--- /dev/null
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module main_test;
+
+       // Inputs
+       reg clk;
+
+       // Outputs
+       wire [7:0] vga_r;
+       wire [7:0] vga_g;
+       wire [7:0] vga_b;
+       wire vga_hsync;
+       wire vga_vsync;
+       wire vga_blank;
+       wire vga_pixel_clock;
+
+       // Instantiate the Unit Under Test (UUT)
+       main uut (
+               .clk(clk), 
+               .vga_r(vga_r), 
+               .vga_g(vga_g), 
+               .vga_b(vga_b), 
+               .vga_hsync(vga_hsync), 
+               .vga_vsync(vga_vsync), 
+               .vga_blank(vga_blank), 
+               .vga_pixel_clock(vga_pixel_clock)
+       );
+
+       initial begin
+               // Initialize Inputs
+               clk = 0;
+
+               // Add stimulus here
+        
+        forever #10 clk = ~clk;
+       end
+    
+    reg [7:0] r;
+    reg [7:0] g;
+    reg [7:0] b;
+    
+    always @(posedge vga_pixel_clock) begin
+        r = vga_r;
+        g = vga_g;
+        b = vga_b;
+    end
+      
+endmodule
+
diff --git a/riscv.vh b/riscv.vh
new file mode 100644 (file)
index 0000000..4b65d14
--- /dev/null
+++ b/riscv.vh
@@ -0,0 +1,175 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`ifndef riscv_vh_
+`define riscv_vh_
+
+`define cause_instruction_address_misaligned 'h0
+`define cause_instruction_access_fault 'h1
+`define cause_illegal_instruction 'h2
+`define cause_breakpoint 'h3
+`define cause_load_address_misaligned 'h4
+`define cause_load_access_fault 'h5
+`define cause_store_amo_address_misaligned 'h6
+`define cause_store_amo_access_fault 'h7
+`define cause_user_environment_call 'h8
+`define cause_supervisor_environment_call 'h9
+`define cause_machine_environment_call 'hB
+`define cause_instruction_page_fault 'hC
+`define cause_load_page_fault 'hD
+`define cause_store_amo_page_fault 'hF
+
+`define opcode_load 7'h03
+`define opcode_load_fp 7'h07
+`define opcode_custom_0 7'h0B
+`define opcode_misc_mem 7'h0F
+`define opcode_op_imm 7'h13
+`define opcode_auipc 7'h17
+`define opcode_op_imm_32 7'h1B
+`define opcode_48b_escape_0 7'h1F
+
+`define opcode_store 7'h23
+`define opcode_store_fp 7'h27
+`define opcode_custom_1 7'h2B
+`define opcode_amo 7'h2F
+`define opcode_op 7'h33
+`define opcode_lui 7'h37
+`define opcode_op_32 7'h3B
+`define opcode_64b_escape 7'h3F
+
+`define opcode_madd 7'h43
+`define opcode_msub 7'h47
+`define opcode_nmsub 7'h4B
+`define opcode_nmadd 7'h4F
+`define opcode_op_fp 7'h53
+`define opcode_reserved_10101 7'h57
+`define opcode_rv128_0 7'h5B
+`define opcode_48b_escape_1 7'h5F
+
+`define opcode_branch 7'h63
+`define opcode_jalr 7'h67
+`define opcode_reserved_11010 7'h6B
+`define opcode_jal 7'h6F
+`define opcode_system 7'h73
+`define opcode_reserved_11101 7'h77
+`define opcode_rv128_1 7'h7B
+`define opcode_80b_escape 7'h7F
+
+`define funct3_jalr 3'h0
+`define funct3_beq 3'h0
+`define funct3_bne 3'h1
+`define funct3_blt 3'h4
+`define funct3_bge 3'h5
+`define funct3_bltu 3'h6
+`define funct3_bgeu 3'h7
+`define funct3_lb 3'h0
+`define funct3_lh 3'h1
+`define funct3_lw 3'h2
+`define funct3_lbu 3'h4
+`define funct3_lhu 3'h5
+`define funct3_sb 3'h0
+`define funct3_sh 3'h1
+`define funct3_sw 3'h2
+`define funct3_addi 3'h0
+`define funct3_slli 3'h1
+`define funct3_slti 3'h2
+`define funct3_sltiu 3'h3
+`define funct3_xori 3'h4
+`define funct3_srli_srai 3'h5
+`define funct3_ori 3'h6
+`define funct3_andi 3'h7
+`define funct3_add_sub 3'h0
+`define funct3_sll 3'h1
+`define funct3_slt 3'h2
+`define funct3_sltu 3'h3
+`define funct3_xor 3'h4
+`define funct3_srl_sra 3'h5
+`define funct3_or 3'h6
+`define funct3_and 3'h7
+`define funct3_fence 3'h0
+`define funct3_fence_i 3'h1
+`define funct3_ecall_ebreak 3'h0
+`define funct3_csrrw 3'h1
+`define funct3_csrrs 3'h2
+`define funct3_csrrc 3'h3
+`define funct3_csrrwi 3'h5
+`define funct3_csrrsi 3'h6
+`define funct3_csrrci 3'h7
+
+`define csr_ustatus 12'h000
+`define csr_fflags 12'h001
+`define csr_frm 12'h002
+`define csr_fcsr 12'h003
+`define csr_uie 12'h004
+`define csr_utvec 12'h005
+`define csr_uscratch 12'h040
+`define csr_uepc 12'h041
+`define csr_ucause 12'h042
+`define csr_utval 12'h043
+`define csr_uip 12'h044
+`define csr_cycle 12'hC00
+`define csr_time 12'hC01
+`define csr_instret 12'hC02
+`define csr_cycleh 12'hC80
+`define csr_timeh 12'hC81
+`define csr_instreth 12'hC82
+
+`define csr_sstatus 12'h100
+`define csr_sedeleg 12'h102
+`define csr_sideleg 12'h103
+`define csr_sie 12'h104
+`define csr_stvec 12'h105
+`define csr_scounteren 12'h106
+`define csr_sscratch 12'h140
+`define csr_sepc 12'h141
+`define csr_scause 12'h142
+`define csr_stval 12'h143
+`define csr_sip 12'h144
+`define csr_satp 12'h180
+
+`define csr_mvendorid 12'hF11
+`define csr_marchid 12'hF12
+`define csr_mimpid 12'hF13
+`define csr_mhartid 12'hF14
+`define csr_mstatus 12'h300
+`define csr_misa 12'h301
+`define csr_medeleg 12'h302
+`define csr_mideleg 12'h303
+`define csr_mie 12'h304
+`define csr_mtvec 12'h305
+`define csr_mcounteren 12'h306
+`define csr_mscratch 12'h340
+`define csr_mepc 12'h341
+`define csr_mcause 12'h342
+`define csr_mtval 12'h343
+`define csr_mip 12'h344
+`define csr_mcycle 12'hB00
+`define csr_minstret 12'hB02
+`define csr_mcycleh 12'hB80
+`define csr_minstreth 12'hB82
+
+`define csr_dcsr 12'h7B0
+`define csr_dpc 12'h7B1
+`define csr_dscratch 12'h7B2
+
+`endif
+
diff --git a/rv32.xise b/rv32.xise
new file mode 100644 (file)
index 0000000..4e8412b
--- /dev/null
+++ b/rv32.xise
@@ -0,0 +1,428 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no" ?>
+<project xmlns="http://www.xilinx.com/XMLSchema" xmlns:xil_pn="http://www.xilinx.com/XMLSchema">
+
+  <header>
+    <!-- ISE source project file created by Project Navigator.             -->
+    <!--                                                                   -->
+    <!-- This file contains project source information including a list of -->
+    <!-- project source files, project and process properties.  This file, -->
+    <!-- along with the project source files, is sufficient to open and    -->
+    <!-- implement in ISE Project Navigator.                               -->
+    <!--                                                                   -->
+    <!-- Copyright (c) 1995-2013 Xilinx, Inc.  All rights reserved. -->
+  </header>
+
+  <version xil_pn:ise_version="14.7" xil_pn:schema_version="2"/>
+
+  <files>
+    <file xil_pn:name="main.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="13"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="13"/>
+    </file>
+    <file xil_pn:name="vga.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="11"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="11"/>
+    </file>
+    <file xil_pn:name="main.ucf" xil_pn:type="FILE_UCF">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+    <file xil_pn:name="font8x8.hex" xil_pn:type="FILE_IMPACT_MISC"/>
+    <file xil_pn:name="vga_clock_generator.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="6"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="6"/>
+    </file>
+    <file xil_pn:name="vga_location_generator.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="4"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="4"/>
+    </file>
+    <file xil_pn:name="vga_text_buffer.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="3"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="3"/>
+    </file>
+    <file xil_pn:name="vga_font_generator.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="5"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="5"/>
+    </file>
+    <file xil_pn:name="main_test.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="14"/>
+      <association xil_pn:name="PostMapSimulation" xil_pn:seqID="106"/>
+      <association xil_pn:name="PostRouteSimulation" xil_pn:seqID="106"/>
+      <association xil_pn:name="PostTranslateSimulation" xil_pn:seqID="106"/>
+    </file>
+    <file xil_pn:name="text_initial.hex" xil_pn:type="FILE_IMPACT_MISC"/>
+    <file xil_pn:name="cpu.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="12"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="12"/>
+    </file>
+    <file xil_pn:name="cpu_memory_interface.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="7"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="7"/>
+    </file>
+    <file xil_pn:name="block_memory.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="2"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="2"/>
+    </file>
+    <file xil_pn:name="cpu_alu.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="10"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="10"/>
+    </file>
+    <file xil_pn:name="cpu_fetch_stage.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="8"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="8"/>
+    </file>
+    <file xil_pn:name="cpu_decoder.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="9"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="9"/>
+    </file>
+    <file xil_pn:name="cpu.bmm" xil_pn:type="FILE_BMM">
+      <association xil_pn:name="Implementation" xil_pn:seqID="0"/>
+    </file>
+    <file xil_pn:name="block_memory_16kbit.v" xil_pn:type="FILE_VERILOG">
+      <association xil_pn:name="BehavioralSimulation" xil_pn:seqID="1"/>
+      <association xil_pn:name="Implementation" xil_pn:seqID="1"/>
+    </file>
+  </files>
+
+  <properties>
+    <property xil_pn:name="AES Initial Vector spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="AES Key (Hex String) spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Add I/O Buffers" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Logic Optimization Across Hierarchy" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow SelectMAP Pins to Persist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unexpanded Blocks" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched LOC Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Allow Unmatched Timing Group Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Analysis Effort Level" xil_pn:value="Standard" xil_pn:valueState="default"/>
+    <property xil_pn:name="Asynchronous To Synchronous" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Auto Implementation Top" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatic BRAM Packing" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Insert glbl Module in the Netlist" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Automatically Run Generate Target PROM/ACE File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="BRAM Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Set/Reset Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bring Out Global Tristate Net as a Port" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Bus Delimiter" xil_pn:value="&lt;>" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case" xil_pn:value="Maintain" xil_pn:valueState="default"/>
+    <property xil_pn:name="Case Implementation Style" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To" xil_pn:value="-2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Change Device Speed To Post Trace" xil_pn:value="-2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Combinatorial Logic Optimization" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile EDK Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile SIMPRIM (Timing) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile UNISIM (Functional) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile XilinxCoreLib (CORE Generator) Simulation Library" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Compile for HDL Debugging" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Clk (Configuration Pins)" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Done" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M0" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M1" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin M2" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Pin Program" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Configuration Rate spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Correlate Output to Input Design" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ASCII Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Binary Configuration File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Bit File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create I/O Pads from Ports" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create IEEE 1532 Configuration File spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Logic Allocation File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create Mask File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Create ReadBack Data Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Cross Clock Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Custom Waveform Configuration File Behav" xil_pn:value="main_test.wcfg" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="DSP Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Delay Values To Be Read from SDF" xil_pn:value="Setup Time" xil_pn:valueState="default"/>
+    <property xil_pn:name="Device" xil_pn:value="xc6slx16" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Family" xil_pn:value="Spartan6" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Device Speed Grade/Select ABS Minimum" xil_pn:value="-2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Disable Detailed Package Model Insertion" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Do Not Escape Signal and Instance Names in Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Done (Output Events)" xil_pn:value="Default (4)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Awake Pin During Suspend/Wake Sequence spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Drive Done Pin High" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable BitStream Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Cyclic Redundancy Checking (CRC) spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Debugging of Serial Mode BitStream" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable External Master Clock spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Hardware Co-Simulation" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Internal Done Pipe" xil_pn:value="true" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Enable Message Filtering" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Multi-Threading" xil_pn:value="2" xil_pn:valueState="non-default" xil_pn:x_locked="true"/>
+    <property xil_pn:name="Enable Multi-Threading par spartan6" xil_pn:value="2" xil_pn:valueState="non-default" xil_pn:x_locked="true"/>
+    <property xil_pn:name="Enable Outputs (Output Events)" xil_pn:value="Default (5)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Enable Suspend/Wake Global Set/Reset spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Encrypt Key Select spartan6" xil_pn:value="BBRAM" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Equivalent Register Removal XST" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Essential Bits" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Evaluation Development Board" xil_pn:value="None Specified" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of Deprecated EDK Cores" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Exclude Compilation of EDK Sub-Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Cost Tables Map" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Extra Effort (Highest PAR level only)" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="FPGA Start-Up Clock" xil_pn:value="CCLK" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Encoding Algorithm" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="FSM Style" xil_pn:value="LUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Filter Files From Compile Order" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Flatten Output Netlist" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language ArchWiz" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Coregen" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Functional Model Target Language Schematic" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="GTS Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="GWE Cycle During Suspend/Wakeup Sequence spartan6" xil_pn:value="5" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Architecture Only (No Entity Declaration)" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Asynchronous Delay Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Clock Region Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Constraints Interaction Report Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Datasheet Section Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Detailed MAP Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Multiple Hierarchical Netlist Files" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place &amp; Route Power Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Post-Place &amp; Route Simulation Model" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate RTL Schematic" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate SAIF File for Power Optimization/Estimation Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Testbench File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generate Timegroups Section Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Generics, Parameters" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization Goal" xil_pn:value="AllClockNets" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Optimization map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Set/Reset Port Name" xil_pn:value="GSR_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Global Tristate Port Name" xil_pn:value="GTS_PORT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Hierarchy Separator" xil_pn:value="/" xil_pn:valueState="default"/>
+    <property xil_pn:name="ISim UUT Instance Name" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Ignore User Timing Constraints Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Implementation Top" xil_pn:value="Module|main" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top File" xil_pn:value="main.v" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Implementation Top Instance Path" xil_pn:value="/main" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Include 'uselib Directive in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include SIMPRIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include UNISIM Models in Verilog File" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Include sdf_annotate task in Verilog File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Incremental Compilation" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Insert Buffers to Prevent Pulse Swallowing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Instantiation Template Target Language Xps" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TCK" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDI" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TDO" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="JTAG Pin TMS" xil_pn:value="Pull Up" xil_pn:valueState="default"/>
+    <property xil_pn:name="Keep Hierarchy" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="LUT Combining Xst" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Language" xil_pn:value="VHDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Last Applied Goal" xil_pn:value="Minimum Runtime" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Last Applied Strategy" xil_pn:value="Runtime Strategy 1;/opt/Xilinx/14.7/ISE_DS/ISE/spartan6/data/spartan6_runtime.xds" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Last Unlock Status" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Launch SDK after Export" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Library for Verilog Sources" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Load glbl" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Manual Implementation Compile Order" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Map Slice Logic into Unused Block RAMs" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Mask Pins for Multi-Pin Wake-Up Suspend Mode spartan6" xil_pn:value="0x00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Max Fanout" xil_pn:value="100000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Compression" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Number of Lines in Report" xil_pn:value="1000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Maximum Signal Name Length" xil_pn:value="20" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move First Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Move Last Flip-Flop Stage" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Insert IPROG CMD in the Bitfile spartan6" xil_pn:value="Enable" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Next Configuration Mode spartan6" xil_pn:value="001" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Golden Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Starting Address for Next Configuration spartan6" xil_pn:value="0x00000000" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: Use New Mode for Next Configuration spartan6" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="MultiBoot: User-Defined Register for Failsafe Scheme spartan6" xil_pn:value="0x0000" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Hierarchy" xil_pn:value="As Optimized" xil_pn:valueState="default"/>
+    <property xil_pn:name="Netlist Translation Type" xil_pn:value="Timestamp" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Clock Buffers" xil_pn:value="16" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Number of Paths in Error/Verbose Report Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimization Effort spartan6" xil_pn:value="High" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Optimization Goal" xil_pn:value="Speed" xil_pn:valueState="default"/>
+    <property xil_pn:name="Optimize Instantiated Primitives" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Bitgen Command Line Options spartan6" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Par" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compiler Options Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Compxlib Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Map Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other NETGEN Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Ngdbuild Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Place &amp; Route Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Behavioral" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other Simulator Commands Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XPWR Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Other XST Command Line Options" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output Extended Identifiers" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Output File Name" xil_pn:value="main" xil_pn:valueState="default"/>
+    <property xil_pn:name="Overwrite Compiled Libraries" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers into IOBs" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Pack I/O Registers/Latches into IOBs" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Package" xil_pn:value="ftg256" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Perform Advanced Analysis" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Advanced Analysis Post Trace" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Perform Timing-Driven Packing and Placement" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place &amp; Route Effort Level (Overall)" xil_pn:value="Standard" xil_pn:valueState="non-default" xil_pn:x_locked="true"/>
+    <property xil_pn:name="Place And Route Mode" xil_pn:value="Normal Place and Route" xil_pn:valueState="default"/>
+    <property xil_pn:name="Place MultiBoot Settings into Bitstream spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Placer Effort Level Map" xil_pn:value="Standard" xil_pn:valueState="non-default" xil_pn:x_locked="true"/>
+    <property xil_pn:name="Placer Extra Effort Map" xil_pn:value="None" xil_pn:valueState="default"/>
+    <property xil_pn:name="Port to be used" xil_pn:value="Auto - default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Map Simulation Model Name" xil_pn:value="main_map.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Place &amp; Route Simulation Model Name" xil_pn:value="main_timesim.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Synthesis Simulation Model Name" xil_pn:value="main_synthesis.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Post Translate Simulation Model Name" xil_pn:value="main_translate.v" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Map spartan6" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Power Reduction Xst" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Preferred Language" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Produce Verbose Report" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Project Description" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Property Specification in Project File" xil_pn:value="Store all values" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="RAM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="ROM Style" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Read Cores" xil_pn:value="false" xil_pn:valueState="non-default" xil_pn:x_locked="true"/>
+    <property xil_pn:name="Reduce Control Sets" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Regenerate Core" xil_pn:value="Under Current Project Setting" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Balancing" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Map" xil_pn:value="Off" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Duplication Xst" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Register Ordering spartan6" xil_pn:value="4" xil_pn:valueState="default"/>
+    <property xil_pn:name="Release Write Enable (Output Events)" xil_pn:value="Default (6)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Design Instance in Testbench File to" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Architecture To" xil_pn:value="Structure" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Entity to" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Rename Top Level Module To" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Fastest Path(s) in Each Constraint Post Trace" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Paths by Endpoint Post Trace" xil_pn:value="3" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Type Post Trace" xil_pn:value="Verbose Report" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Report Unconstrained Paths Post Trace" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Reset On Configuration Pulse Width" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Resource Sharing" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retain Hierarchy" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Retry Configuration if CRC Error Occurs spartan6" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select" xil_pn:value="00" xil_pn:valueState="default"/>
+    <property xil_pn:name="Revision Select Tristate" xil_pn:value="Disable" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run Design Rules Checker (DRC)" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Map" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Par" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Run for Specified Time Translate" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Safe Implementation" xil_pn:value="No" xil_pn:valueState="default"/>
+    <property xil_pn:name="Security" xil_pn:value="Enable Readback and Reconfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Module Instance Name" xil_pn:value="/main_test" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Behavioral" xil_pn:value="work.main_test" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Map" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Route" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Root Source Node Post-Translate" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Selected Simulation Source Node" xil_pn:value="UUT" xil_pn:valueState="default"/>
+    <property xil_pn:name="Set SPI Configuration Bus Width spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Setup External Master Clock Division spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Extraction" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Shift Register Minimum Size spartan6" xil_pn:value="2" xil_pn:valueState="default"/>
+    <property xil_pn:name="Show All Models" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Model Target" xil_pn:value="Verilog" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time ISim" xil_pn:value="30 us" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Simulation Run Time Map" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Par" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulation Run Time Translate" xil_pn:value="1000 ns" xil_pn:valueState="default"/>
+    <property xil_pn:name="Simulator" xil_pn:value="ISim (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Slice Utilization Ratio" xil_pn:value="100" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify 'define Macro Name and Value" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Behavioral" xil_pn:value="work.main_test" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Map" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Route" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Specify Top Level Instance Names Post-Translate" xil_pn:value="Default" xil_pn:valueState="default"/>
+    <property xil_pn:name="Speed Grade" xil_pn:value="-2" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Starting Placer Cost Table (1-100) Map spartan6" xil_pn:value="1" xil_pn:valueState="default"/>
+    <property xil_pn:name="Synthesis Tool" xil_pn:value="XST (VHDL/Verilog)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Target Simulator" xil_pn:value="Please Specify" xil_pn:valueState="default"/>
+    <property xil_pn:name="Target UCF File Name" xil_pn:value="main.ucf" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Timing Mode Map" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Timing Mode Par" xil_pn:value="Performance Evaluation" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Module Name in Output Netlist" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Top-Level Source Type" xil_pn:value="HDL" xil_pn:valueState="default"/>
+    <property xil_pn:name="Trim Unconnected Signals" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Tristate On Configuration Pulse Width" xil_pn:value="0" xil_pn:valueState="default"/>
+    <property xil_pn:name="Unused IOB Pins" xil_pn:value="Pull Down" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use 64-bit PlanAhead on 64-bit Systems" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Clock Enable" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Route" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Project File Post-Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Behavioral" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Simulation Command File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Behav" xil_pn:value="true" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Map" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Par" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Custom Waveform Configuration File Translate" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use DSP Block spartan6" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use LOC Constraints" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use RLOC Constraints" xil_pn:value="Yes" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Smart Guide" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Reset" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synchronous Set" xil_pn:value="Auto" xil_pn:valueState="default"/>
+    <property xil_pn:name="Use Synthesis Constraints File" xil_pn:value="true" xil_pn:valueState="default"/>
+    <property xil_pn:name="User Browsed Strategy Files" xil_pn:value="/opt/Xilinx/14.7/ISE_DS/ISE/data/default.xds" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="UserID Code (8 Digit Hexadecimal)" xil_pn:value="0xFFFFFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="VCCAUX Voltage Level spartan6" xil_pn:value="2.5V" xil_pn:valueState="default"/>
+    <property xil_pn:name="VHDL Source Analysis Standard" xil_pn:value="VHDL-93" xil_pn:valueState="default"/>
+    <property xil_pn:name="Value Range Check" xil_pn:value="false" xil_pn:valueState="default"/>
+    <property xil_pn:name="Verilog Macros" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wait for DCM and PLL Lock (Output Events) spartan6" xil_pn:value="Default (NoWait)" xil_pn:valueState="default"/>
+    <property xil_pn:name="Wakeup Clock spartan6" xil_pn:value="Startup Clock" xil_pn:valueState="default"/>
+    <property xil_pn:name="Watchdog Timer Value spartan6" xil_pn:value="0xFFFF" xil_pn:valueState="default"/>
+    <property xil_pn:name="Working Directory" xil_pn:value="." xil_pn:valueState="non-default"/>
+    <property xil_pn:name="Write Timing Constraints" xil_pn:value="false" xil_pn:valueState="default"/>
+    <!--                                                                                  -->
+    <!-- The following properties are for internal use only. These should not be modified.-->
+    <!--                                                                                  -->
+    <property xil_pn:name="PROP_BehavioralSimTop" xil_pn:value="Module|main_test" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_DesignName" xil_pn:value="rv32" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_DevFamilyPMName" xil_pn:value="spartan6" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_FPGAConfiguration" xil_pn:value="FPGAConfiguration" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostMapSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostParSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostSynthSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PostXlateSimTop" xil_pn:value="" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_PreSynthesis" xil_pn:value="PreSynthesis" xil_pn:valueState="default"/>
+    <property xil_pn:name="PROP_intProjectCreationTimestamp" xil_pn:value="2018-03-12T08:17:29" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWbtProjectID" xil_pn:value="A745DC73C540110432FA7EE27F1D769D" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirLocWRTProjDir" xil_pn:value="Same" xil_pn:valueState="non-default"/>
+    <property xil_pn:name="PROP_intWorkingDirUsed" xil_pn:value="No" xil_pn:valueState="non-default"/>
+  </properties>
+
+  <bindings/>
+
+  <libraries/>
+
+  <autoManagedFiles>
+    <!-- The following files are identified by `include statements in verilog -->
+    <!-- source files and are automatically managed by Project Navigator.     -->
+    <!--                                                                      -->
+    <!-- Do not hand-edit this section, as it will be overwritten when the    -->
+    <!-- project is analyzed based on files automatically identified as       -->
+    <!-- include files.                                                       -->
+    <file xil_pn:name="riscv.vh" xil_pn:type="FILE_VERILOG"/>
+    <file xil_pn:name="cpu.vh" xil_pn:type="FILE_VERILOG"/>
+  </autoManagedFiles>
+
+</project>
diff --git a/software/.clang-format b/software/.clang-format
new file mode 100644 (file)
index 0000000..c65d7a3
--- /dev/null
@@ -0,0 +1,65 @@
+---
+Language: Cpp
+BasedOnStyle: Google
+AccessModifierOffset: -4
+AlignAfterOpenBracket: true
+AlignConsecutiveAssignments: false
+AlignEscapedNewlinesLeft: true
+AlignOperands: true
+AlignTrailingComments: false
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: false
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: true
+BinPackArguments: false
+BinPackParameters: false
+BreakBeforeBinaryOperators: NonAssignment
+BreakBeforeBraces: Allman
+BreakBeforeTernaryOperators: false
+BreakConstructorInitializersBeforeComma: false
+ColumnLimit: 100
+CommentPragmas:  '^ IWYU pragma:'
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DerivePointerAlignment: false
+DisableFormat: false
+ForEachMacros:   [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IndentCaseLabels: false
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd:   ''
+MaxEmptyLinesToKeep: 2
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 4
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: false
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Right
+SpaceAfterCStyleCast: false
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeParens: Never
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 1
+SpacesInAngles: false
+SpacesInCStyleCastParentheses: false
+SpacesInContainerLiterals: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+Standard: Cpp11
+TabWidth: 8
+UseTab: Never
+...
diff --git a/software/.gitignore b/software/.gitignore
new file mode 100644 (file)
index 0000000..bab65d9
--- /dev/null
@@ -0,0 +1,8 @@
+emulated
+generate_hex_files.sh
+*.o
+ram.bin
+*.elf
+ram_?_byte?.hex
+
+
diff --git a/software/Makefile b/software/Makefile
new file mode 100644 (file)
index 0000000..7b5ecce
--- /dev/null
@@ -0,0 +1,55 @@
+# Copyright 2018 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+.PHONY: all clean
+
+LIBGCC := $(shell riscv32-unknown-elf-g++ -print-libgcc-file-name)
+LIBGCC_DIR := $(dir $(LIBGCC))
+
+all: ram0_byte0.hex ../output.bit emulated
+../output.bit: ram.elf ../main.bit
+       bash -c '. /opt/Xilinx/14.7/ISE_DS/settings64.sh; data2mem -bm ../cpu.bmm -bd ram.elf -bt ../main.bit -o b ../output.bit'
+ram0_byte0.hex: ram.bin generate_hex_files.sh Makefile
+       ./generate_hex_files.sh
+generate_hex_files.sh: make_block_memory.sh
+       ./make_block_memory.sh -s
+ram.bin: ram-stripped.elf Makefile
+       riscv32-unknown-elf-objcopy -O binary --pad-to 0x18000 ram.elf ram.bin
+OBJECTS := main.o \
+           start.o \
+           startup.o
+ram-stripped.elf: Makefile ram.elf
+       riscv32-unknown-elf-strip -o ram-stripped.elf ram.elf
+ram.elf: $(OBJECTS) Makefile ram.ld
+       riscv32-unknown-elf-ld -o ram.elf $(OBJECTS) -static -T ram.ld -L$(LIBGCC_DIR) -L/opt/riscv/riscv32-unknown-elf/lib -lgcc -lc
+startup.o: startup.S Makefile
+       riscv32-unknown-elf-g++ -c -o startup.o startup.S -march=rv32i -mabi=ilp32
+main.o: main.cpp Makefile
+start.o: start.cpp Makefile
+main-emulated.o: main.cpp Makefile
+       g++ -g -c -o main-emulated.o -std=c++14 -Wall main.cpp -DEMULATE_TARGET
+emulated: main-emulated.o Makefile
+       g++ -g -o emulated -std=c++14 -Wall main-emulated.o -static
+
+%.o: %.cpp
+       riscv32-unknown-elf-g++ -Os -c -o $@ $< -std=c++14 -Wall -march=rv32i -mabi=ilp32 -fno-exceptions
+
+clean:
+       rm -f ram*.hex ram.bin ram.elf ram-stripped.elf *.o emulated generate_hex_files.sh
diff --git a/software/main.cpp b/software/main.cpp
new file mode 100644 (file)
index 0000000..4c13aa0
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <cstdint>
+#include <limits>
+
+inline void putchar(int ch)
+{
+#ifdef EMULATE_TARGET
+    switch(ch)
+    {
+    case 0xB2:
+        __builtin_printf("\u2593");
+        break;
+    case 0xB0:
+        __builtin_printf("\u2591");
+        break;
+    default:
+        __builtin_printf("%c", (char)ch);
+    }
+#else
+    *reinterpret_cast<volatile char *>(0x80000000) = ch;
+#endif
+}
+
+inline void write_hex_digit(int value)
+{
+    putchar("0123456789ABCDEF"[value]);
+}
+
+inline void write_hex_u8(std::uint8_t value)
+{
+    write_hex_digit(value >> 4);
+    write_hex_digit(value & 0xF);
+}
+
+inline void write_hex_u16(std::uint16_t value)
+{
+    write_hex_u8(value >> 8);
+    write_hex_u8(value & 0xFF);
+}
+
+inline void write_hex_u32(std::uint32_t value)
+{
+    write_hex_u16(value >> 16);
+    write_hex_u16(value & 0xFFFF);
+}
+
+inline std::uint32_t read_gpio()
+{
+#ifdef EMULATE_TARGET
+    return 0x0;
+#else
+    return *reinterpret_cast<volatile std::uint32_t *>(0x80000010);
+#endif
+}
+
+inline void write_gpio(std::uint32_t value)
+{
+#ifndef EMULATE_TARGET
+    *reinterpret_cast<volatile std::uint32_t *>(0x80000010) = value;
+#endif
+}
+
+constexpr std::uint32_t switch_2_mask = 0x200;
+constexpr std::uint32_t switch_3_mask = 0x400;
+
+inline void puts(const char *str)
+{
+    while(*str)
+        putchar(*str++);
+}
+
+constexpr std::size_t screen_x_size = 800 / 8;
+constexpr std::size_t screen_y_size = 600 / 8;
+
+template <typename T>
+struct get_double_length_type;
+
+template <>
+struct get_double_length_type<std::uint8_t>
+{
+    typedef std::uint16_t type;
+};
+
+template <>
+struct get_double_length_type<std::uint16_t>
+{
+    typedef std::uint32_t type;
+};
+
+template <>
+struct get_double_length_type<std::uint32_t>
+{
+    typedef std::uint64_t type;
+};
+
+template <>
+struct get_double_length_type<std::int8_t>
+{
+    typedef std::int16_t type;
+};
+
+template <>
+struct get_double_length_type<std::int16_t>
+{
+    typedef std::int32_t type;
+};
+
+template <>
+struct get_double_length_type<std::int32_t>
+{
+    typedef std::int64_t type;
+};
+
+template <typename T>
+constexpr T bidirectional_shift_left(T value, int amount) noexcept
+{
+    int max_shift = std::numeric_limits<T>::digits;
+    if(amount <= -max_shift)
+        return value < 0 ? -1 : 0;
+    if(amount < 0)
+        return value >> -amount;
+    return value << amount;
+}
+
+template <typename T>
+constexpr T bidirectional_shift_right(T value, int amount) noexcept
+{
+    return bidirectional_shift_left(value, -amount);
+}
+
+template <typename T = std::int32_t, std::size_t FractionalBits = 16>
+class Fixed
+{
+public:
+    typedef T underlying_type;
+    typedef typename get_double_length_type<T>::type double_length_type;
+    static constexpr std::size_t total_bits = std::numeric_limits<T>::digits;
+    static constexpr std::size_t fractional_bits = FractionalBits;
+    static constexpr std::size_t integer_bits = total_bits - fractional_bits;
+    static constexpr T fraction_mask = (static_cast<T>(1) << fractional_bits) - 1;
+    static constexpr T integer_mask = ~fraction_mask;
+    static_assert(total_bits >= fractional_bits, "");
+
+private:
+    underlying_type value;
+
+public:
+    constexpr Fixed() noexcept : value(0)
+    {
+    }
+    constexpr Fixed(signed char v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(short v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(int v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(long v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(long long v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(unsigned char v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(char v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(unsigned short v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(unsigned v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(unsigned long v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(unsigned long long v) noexcept : value(static_cast<T>(v) << fractional_bits)
+    {
+    }
+    constexpr Fixed(float v) noexcept
+        : value(static_cast<T>(static_cast<float>(1ULL << fractional_bits) * v))
+    {
+    }
+    constexpr Fixed(double v) noexcept
+        : value(static_cast<T>(static_cast<double>(1ULL << fractional_bits) * v))
+    {
+    }
+    constexpr explicit operator T() const noexcept
+    {
+        if(value < 0)
+            return (value + fraction_mask) >> fractional_bits;
+        return value >> fractional_bits;
+    }
+    constexpr explicit operator double() const noexcept
+    {
+        return value * (1.0 / (1ULL << fractional_bits));
+    }
+    static constexpr Fixed make(T underlying_value) noexcept
+    {
+        Fixed retval;
+        retval.value = underlying_value;
+        return retval;
+    }
+    constexpr Fixed operator+() const noexcept
+    {
+        return *this;
+    }
+    constexpr Fixed operator-() const noexcept
+    {
+        return make(-value);
+    }
+    friend constexpr Fixed operator+(Fixed a, Fixed b) noexcept
+    {
+        return make(a.value + b.value);
+    }
+    friend constexpr Fixed operator-(Fixed a, Fixed b) noexcept
+    {
+        return make(a.value - b.value);
+    }
+    friend constexpr Fixed operator*(Fixed a, Fixed b) noexcept
+    {
+        return make(static_cast<double_length_type>(a.value) * b.value >> fractional_bits);
+    }
+    friend constexpr Fixed operator/(Fixed a, Fixed b) noexcept
+    {
+        return make((static_cast<double_length_type>(a.value) << fractional_bits) / b.value);
+    }
+    constexpr Fixed &operator+=(Fixed rt) noexcept
+    {
+        return *this = *this + rt;
+    }
+    constexpr Fixed &operator-=(Fixed rt) noexcept
+    {
+        return *this = *this - rt;
+    }
+    constexpr Fixed &operator*=(Fixed rt) noexcept
+    {
+        return *this = *this * rt;
+    }
+    constexpr Fixed &operator/=(Fixed rt) noexcept
+    {
+        return *this = *this / rt;
+    }
+    constexpr T underlying_value() const noexcept
+    {
+        return value;
+    }
+    friend constexpr bool operator==(Fixed a, Fixed b) noexcept
+    {
+        return a.value == b.value;
+    }
+    friend constexpr bool operator!=(Fixed a, Fixed b) noexcept
+    {
+        return a.value != b.value;
+    }
+    friend constexpr bool operator<=(Fixed a, Fixed b) noexcept
+    {
+        return a.value <= b.value;
+    }
+    friend constexpr bool operator>=(Fixed a, Fixed b) noexcept
+    {
+        return a.value >= b.value;
+    }
+    friend constexpr bool operator<(Fixed a, Fixed b) noexcept
+    {
+        return a.value < b.value;
+    }
+    friend constexpr bool operator>(Fixed a, Fixed b) noexcept
+    {
+        return a.value > b.value;
+    }
+    friend constexpr Fixed floor(Fixed v) noexcept
+    {
+        v.value &= integer_mask;
+        return v;
+    }
+    friend constexpr Fixed fracf(Fixed v) noexcept
+    {
+        v.value &= fraction_mask;
+        return v;
+    }
+    friend constexpr Fixed ceil(Fixed v) noexcept
+    {
+        v.value += fraction_mask;
+        return floor(v);
+    }
+    friend constexpr Fixed round(Fixed v) noexcept
+    {
+        constexpr Fixed one_half = 0.5;
+        v += one_half;
+        return floor(v);
+    }
+    friend constexpr T floori(Fixed v) noexcept
+    {
+        return v.value >> fractional_bits;
+    }
+    friend constexpr T ceili(Fixed v) noexcept
+    {
+        v.value += fraction_mask;
+        return floori(v);
+    }
+    friend constexpr T roundi(Fixed v) noexcept
+    {
+        constexpr Fixed one_half = 0.5;
+        v += one_half;
+        return floori(v);
+    }
+    friend constexpr Fixed abs(Fixed v) noexcept
+    {
+        if(v.value < 0)
+            return -v;
+        return v;
+    }
+    friend constexpr Fixed sqrt(Fixed v) noexcept
+    {
+        if(v <= 0)
+            return 0;
+        Fixed guess = 0;
+        double_length_type guess_squared = 0;
+        for(int bit_index = (integer_bits + 1) / 2; bit_index >= -static_cast<int>(fractional_bits);
+            bit_index--)
+        {
+            Fixed new_guess = guess + make(static_cast<T>(1) << (bit_index + fractional_bits));
+            double_length_type new_guess_squared = guess_squared;
+            new_guess_squared += bidirectional_shift_left(
+                static_cast<double_length_type>(guess.value), bit_index + 1);
+            new_guess_squared += bidirectional_shift_left(
+                static_cast<double_length_type>(Fixed(1).value), 2 * bit_index);
+            if(new_guess_squared < v.value)
+            {
+                guess = new_guess;
+                guess_squared = new_guess_squared;
+            }
+            else if(new_guess_squared == v.value)
+                return new_guess;
+        }
+        return guess;
+    }
+};
+
+enum class Block : char
+{
+    Empty = ' ',
+    Wall = '|',
+    End = 'X'
+};
+
+constexpr double constexpr_sin2pi(double x) noexcept
+{
+    x -= static_cast<long long>(x);
+    if(x < 0)
+        x += 1;
+    if(x == 0)
+        return 0;
+    if(x == 0.25)
+        return 1;
+    if(x == 0.5)
+        return 0;
+    if(x == 0.75)
+        return -1;
+    double x2 = x * x;
+    const double coefficients[] = {
+        1.5873670538243229332222957023504872028033458258785e-8,
+        -3.2649283479971170585768247133750680886632233028762e-7,
+        5.8056524029499061679627827975252772363553363262495e-6,
+        -8.8235335992430051344844841671401871742374913922057e-5,
+        1.1309237482517961877702180414488525515732161905954e-3,
+        -1.2031585942120627233202567845286556653885737182738e-2,
+        1.0422916220813984117271044898760411097029995316417e-1,
+        -7.1812230177850051223174027860686238053986168884284e-1,
+        3.8199525848482821277337920673404661254406128731422,
+        -1.5094642576822990391826616232531520514481435107371e1,
+        4.205869394489765314498681114813355254161277992845e1,
+        -7.6705859753061385841630641093893125889966539055122e1,
+        8.1605249276075054203397682678249495061413521767487e1,
+        -4.1341702240399760233968420089468526936300384754514e1,
+        6.2831853071795864769252867665590057683943387987502,
+    };
+    double v = 0;
+    for(double coeff : coefficients)
+        v = v * x2 + coeff;
+    return x * v;
+}
+
+constexpr double constexpr_cos2pi(double x) noexcept
+{
+    x -= static_cast<long long>(x);
+    x += 0.25;
+    return constexpr_sin2pi(x);
+}
+
+template <std::size_t N = 65>
+struct SinCosList
+{
+    static_assert(N > 1, "");
+    constexpr std::size_t size() const noexcept
+    {
+        return N;
+    }
+    Fixed<> sin_table[N];
+    constexpr SinCosList() noexcept : sin_table{}
+    {
+        for(std::size_t i = 0; i < N; i++)
+        {
+            double rotations = i / (4.0 * (N - 1));
+            sin_table[i] = constexpr_sin2pi(rotations);
+        }
+    }
+    constexpr void get(Fixed<> &sin_out, Fixed<> &cos_out, Fixed<> rotations) const noexcept
+    {
+        rotations = fracf(rotations) * 4;
+        int quadrent = floori(rotations);
+        rotations = (N - 1) * fracf(rotations);
+        auto int_part = floori(rotations);
+        auto fraction = fracf(rotations);
+        auto sin_value =
+            sin_table[int_part] + fraction * (sin_table[int_part + 1] - sin_table[int_part]);
+        auto cos_value =
+            sin_table[N - 1 - int_part]
+            + fraction * (sin_table[N - 1 - int_part - 1] - sin_table[N - 1 - int_part]);
+        switch(quadrent)
+        {
+        case 1:
+            sin_out = cos_value;
+            cos_out = -sin_value;
+            break;
+        case 2:
+            sin_out = -sin_value;
+            cos_out = -cos_value;
+            break;
+        case 3:
+            sin_out = -cos_value;
+            cos_out = sin_value;
+            break;
+        default:
+            sin_out = sin_value;
+            cos_out = cos_value;
+            break;
+        }
+    }
+    constexpr Fixed<> get_sin(Fixed<> rotations) const noexcept
+    {
+        Fixed<> sin, cos;
+        get(sin, cos, rotations);
+        return sin;
+    }
+    constexpr Fixed<> get_cos(Fixed<> rotations) const noexcept
+    {
+        Fixed<> sin, cos;
+        get(sin, cos, rotations);
+        return cos;
+    }
+};
+
+constexpr auto sin_cos_list = SinCosList<>();
+
+constexpr void rotate(Fixed<> &x, Fixed<> &y, Fixed<> rotations)
+{
+    Fixed<> sin, cos;
+    sin_cos_list.get(sin, cos, rotations);
+    auto new_x = x * cos - y * sin;
+    auto new_y = x * sin + y * cos;
+    x = new_x;
+    y = new_y;
+}
+
+inline void write_fixed(Fixed<> v)
+{
+    write_hex_u32(floori(v));
+    putchar('.');
+    write_hex_u16(floori(fracf(v) * 0x10000));
+}
+
+template <typename T>
+struct Vec2D
+{
+    typedef T element_type;
+    T x, y;
+    constexpr Vec2D() noexcept : x(), y()
+    {
+    }
+    constexpr explicit Vec2D(T v) noexcept : x(v), y(v)
+    {
+    }
+    constexpr Vec2D(T x, T y) noexcept : x(x), y(y)
+    {
+    }
+    friend constexpr Vec2D operator+(Vec2D a, Vec2D b) noexcept
+    {
+        return Vec2D(a.x + b.x, a.y + b.y);
+    }
+    friend constexpr Vec2D operator-(Vec2D a, Vec2D b) noexcept
+    {
+        return Vec2D(a.x - b.x, a.y - b.y);
+    }
+    friend constexpr Vec2D operator*(T a, Vec2D b) noexcept
+    {
+        return Vec2D(a * b.x, a * b.y);
+    }
+    friend constexpr Vec2D operator*(Vec2D a, T b) noexcept
+    {
+        return Vec2D(a.x * b, a.y * b);
+    }
+    friend constexpr Vec2D operator/(Vec2D a, T b) noexcept
+    {
+        return Vec2D(a.x / b, a.y / b);
+    }
+    constexpr Vec2D &operator+=(Vec2D rt) noexcept
+    {
+        return *this = *this + rt;
+    }
+    constexpr Vec2D &operator-=(Vec2D rt) noexcept
+    {
+        return *this = *this - rt;
+    }
+    constexpr Vec2D &operator*=(T rt) noexcept
+    {
+        return *this = *this * rt;
+    }
+    constexpr Vec2D &operator/=(T rt) noexcept
+    {
+        return *this = *this / rt;
+    }
+};
+
+constexpr Vec2D<Fixed<>> rotate(Vec2D<Fixed<>> v, Fixed<> rotations) noexcept
+{
+    rotate(v.x, v.y, rotations);
+    return v;
+}
+
+constexpr void init_ray_cast_dimension(Fixed<> ray_direction,
+                                       Fixed<> ray_start_position,
+                                       std::int32_t current_position,
+                                       Fixed<> &next_t,
+                                       Fixed<> &step_t,
+                                       std::int32_t &delta_position)
+{
+    if(ray_direction == 0)
+        return;
+    auto inverse_direction = 1 / ray_direction;
+    step_t = abs(inverse_direction);
+    std::int32_t target_position{};
+    if(ray_direction < 0)
+    {
+        target_position = ceili(ray_start_position) - 1;
+        delta_position = -1;
+    }
+    else
+    {
+        target_position = floori(ray_start_position) + 1;
+        delta_position = 1;
+    }
+    next_t = (target_position - ray_start_position) * inverse_direction;
+}
+
+struct RayCaster
+{
+    Vec2D<Fixed<>> ray_start_position;
+    Vec2D<Fixed<>> ray_direction;
+    Vec2D<std::int32_t> current_position;
+    Fixed<> current_t;
+    Vec2D<Fixed<>> next_t;
+    Vec2D<Fixed<>> step_t;
+    Vec2D<std::int32_t> delta_position;
+    int last_hit_dimension = -1;
+    constexpr RayCaster(Vec2D<Fixed<>> ray_start_position, Vec2D<Fixed<>> ray_direction) noexcept
+        : ray_start_position(ray_start_position),
+          ray_direction(ray_direction),
+          current_position(floori(ray_start_position.x), floori(ray_start_position.y)),
+          current_t(Fixed<>::make(1)),
+          next_t(0),
+          step_t(0),
+          delta_position(0)
+    {
+        init_ray_cast_dimension(ray_direction.x,
+                                ray_start_position.x,
+                                current_position.x,
+                                next_t.x,
+                                step_t.x,
+                                delta_position.x);
+        init_ray_cast_dimension(ray_direction.y,
+                                ray_start_position.y,
+                                current_position.y,
+                                next_t.y,
+                                step_t.y,
+                                delta_position.y);
+    }
+    constexpr void step() noexcept
+    {
+        if(ray_direction.x != 0 && (ray_direction.y == 0 || next_t.x < next_t.y))
+        {
+            current_t = next_t.x;
+            next_t.x += step_t.x;
+            current_position.x += delta_position.x;
+            last_hit_dimension = 0;
+        }
+        else if(ray_direction.y != 0)
+        {
+            current_t = next_t.y;
+            next_t.y += step_t.y;
+            current_position.y += delta_position.y;
+            last_hit_dimension = 1;
+        }
+    }
+};
+
+int main()
+{
+    static std::uint8_t start_col[screen_x_size] = {}, end_col[screen_x_size] = {};
+    static char col_color[screen_x_size] = {};
+    constexpr std::size_t world_x_size = 16, world_z_size = 16;
+    static const char world[world_x_size][world_z_size] = {
+    // clang-format off
+        {'|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', 'X', 'X'},
+        {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', ' ', 'X'},
+        {'|', ' ', '|', '|', '|', '|', '|', '|', '|', ' ', ' ', '|', ' ', ' ', ' ', 'X'},
+        {'|', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', '|', 'X', 'X'},
+        {'|', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', '|', '|', '|'},
+        {'|', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', '|', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', '|', '|', ' ', '|'},
+        {'|', ' ', '|', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', '|', '|', '|', '|', '|', '|', '|', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', '|', '|', '|', '|', '|', '|', '|', ' ', ' ', '|', ' ', ' ', ' ', '|'},
+        {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'},
+        {'|', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', '|'},
+        {'|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|', '|'},
+    // clang-format on
+    };
+    Vec2D<Fixed<>> view_position(1.5, 1.5);
+    Fixed<> view_angle(0);
+    std::uint32_t flash_counter = 0;
+    constexpr std::uint32_t flash_period = 10;
+    while(true)
+    {
+        flash_counter++;
+        if(flash_counter >= flash_period)
+            flash_counter = 0;
+        if(read_gpio() & switch_2_mask)
+        {
+            view_angle += 0.01;
+            view_angle = fracf(view_angle);
+        }
+        if(read_gpio() & switch_3_mask)
+        {
+            Vec2D<Fixed<>> forward(0, 0.05);
+            forward = rotate(forward, view_angle);
+            auto new_view_position = view_position + forward;
+            Vec2D<std::int32_t> new_block_position(floori(new_view_position.x),
+                                                   floori(new_view_position.y));
+#if 1
+            auto block = world[new_block_position.x][new_block_position.y];
+            if(block == ' ')
+                view_position = new_view_position;
+#else
+            Fixed<> closest_distance(100);
+            for(int dx = -1; dx <= 1; dx++)
+            {
+                for(int dy = -1; dy <= 1; dy++)
+                {
+                    auto block_position = new_block_position;
+                    block_position.x += dx;
+                    block_position.y += dy;
+                    auto block = world[block_position.x][block_position.y];
+                    if(block == ' ')
+                        continue;
+                    auto closest_position = new_view_position;
+                    if(closest_position.x < block_position.x)
+                        closest_position.x = block_position.x;
+                    else if(closest_position.x > block_position.x + 1)
+                        closest_position.x = block_position.x + 1;
+                    if(closest_position.y < block_position.y)
+                        closest_position.y = block_position.y;
+                    else if(closest_position.y > block_position.y + 1)
+                        closest_position.y = block_position.y + 1;
+                    auto current_distance_x = abs(closest_position.x - block_position.x);
+                    auto current_distance_y = abs(closest_position.y - block_position.y);
+                    auto current_distance = current_distance_x;
+                    if(current_distance < current_distance_y)
+                        current_distance = current_distance_y;
+                    if(current_distance < closest_distance)
+                        closest_distance = current_distance;
+                }
+            }
+            if(closest_distance >= 0.1)
+                view_position = new_view_position;
+#endif
+        }
+        for(std::size_t x = 0; x < screen_x_size; x++)
+        {
+            Vec2D<Fixed<>> ray_direction(
+                (Fixed<>(x) + (0.5 - screen_x_size / 2.0)) * (2.0 / screen_x_size), 1);
+            ray_direction = rotate(ray_direction, view_angle);
+            RayCaster ray_caster(view_position, ray_direction);
+            auto hit_block = world[ray_caster.current_position.x][ray_caster.current_position.y];
+            while(hit_block == ' ')
+            {
+                ray_caster.step();
+                hit_block = world[ray_caster.current_position.x][ray_caster.current_position.y];
+            }
+            constexpr Fixed<> max_height = 10;
+            Fixed<> height = ray_caster.current_t != Fixed<>::make(1) ?
+                                 1 / ray_caster.current_t :
+                                 max_height;
+            if(height > max_height)
+                height = max_height;
+            height *= screen_x_size / 2.0;
+            auto iheight = roundi(height);
+            if(iheight > static_cast<int>(screen_y_size))
+                iheight = screen_y_size;
+            else if(iheight < 0)
+                iheight = 0;
+            start_col[x] = screen_y_size / 2 - iheight / 2;
+            end_col[x] = screen_y_size / 2 + (iheight + 1) / 2;
+            col_color[x] = 0xB0;
+            if(hit_block == 'X' && flash_counter >= flash_period / 2)
+            {
+                col_color[x] = '#';
+                if(ray_caster.last_hit_dimension == 0)
+                    col_color[x] = 'X';
+            }
+            else if(ray_caster.last_hit_dimension == 0)
+            {
+                col_color[x] = 0xB1;
+            }
+        }
+        puts("\x1B[H");
+        for(std::size_t y = 0; y < screen_y_size; y++)
+        {
+            for(std::size_t x = 0,
+                            x_end = (y == screen_y_size - 1 ? screen_x_size - 1 : screen_x_size);
+                x < x_end;
+                x++)
+            {
+                if(y >= end_col[x])
+                    putchar(0xB2);
+                else if(y >= start_col[x])
+                    putchar(col_color[x]);
+                else
+                    putchar(0x20);
+            }
+        }
+    }
+}
diff --git a/software/make_block_memory.sh b/software/make_block_memory.sh
new file mode 100755 (executable)
index 0000000..4103268
--- /dev/null
@@ -0,0 +1,198 @@
+#!/bin/bash
+# Copyright 2018 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# 32KiB
+memory_size=$((32<<10))
+# 16kbit
+block_size_log_2=11
+
+output_file=""
+
+function open_output_file()
+{
+    output_file="$1"
+    exec >"$1"
+}
+
+function error()
+{
+    echo "error:" "$@" >&2
+    if [[ "" != "$output_file" ]]; then
+        rm "$output_file"
+    fi
+    exit 1
+}
+
+chunk_size_log_2=$((block_size_log_2+2))
+chunk_size=$((1<<chunk_size_log_2))
+chunk_count=$((memory_size / chunk_size))
+((memory_size % chunk_size == 0)) || error "memory_size must be a multiple of chunk_size"
+
+if [[ "$1" == "-v" ]]; then
+    open_output_file block_memory.v
+    cat <<EOF
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+\`timescale 1ns / 1ps
+
+module block_memory(
+    input clk,
+    input [31:0] a_ram_address,
+    input [3:0] a_write_enable,
+    input [31:0] a_write_input,
+    output reg [31:0] a_read_output,
+    input [31:0] b_ram_address,
+    output reg [31:0] b_read_output
+    );
+EOF
+
+    for((i = 0; i < chunk_count; i++)); do
+        cat <<EOF
+
+    wire a_enable_${i} = a_ram_address[31:${block_size_log_2}] == ${i};
+    wire b_enable_${i} = b_ram_address[31:${block_size_log_2}] == ${i};
+    wire [3:0] a_write_enable_${i} = {4{a_enable_${i}}} & a_write_enable;
+    wire [31:0] a_read_output_${i};
+    wire [31:0] b_read_output_${i};
+EOF
+        for byte in {0..3}; do
+            cat <<EOF
+    block_memory_16kbit #(
+        .initial_file("software/ram_${i}_byte${byte}.hex")
+        ) ram_${i}_byte${byte}(
+        .clk(clk),
+        .port_a_address(a_ram_address[$((block_size_log_2 - 1)):0]),
+        .port_a_write_enable(a_write_enable_${i}[${byte}]),
+        .port_a_write_input(a_write_input[$((byte * 8 + 7)):$((byte * 8))]),
+        .port_a_read_output(a_read_output_${i}[$((byte * 8 + 7)):$((byte * 8))]),
+        .port_b_address(b_ram_address[$((block_size_log_2 - 1)):0]),
+        .port_b_read_output(b_read_output_${i}[$((byte * 8 + 7)):$((byte * 8))])
+        );
+
+EOF
+        done
+    done
+
+    cat <<EOF
+
+    always @* begin
+        case(a_ram_address[31:${block_size_log_2}])
+EOF
+
+    for((i = 0; i < chunk_count; i++)); do
+    cat <<EOF
+        ${i}: a_read_output = a_read_output_${i};
+EOF
+    done
+
+    cat <<EOF
+        default: a_read_output = 32'hXXXXXXXX;
+        endcase
+    end
+
+    always @* begin
+        case(b_ram_address[31:${block_size_log_2}])
+EOF
+
+    for((i = 0; i < chunk_count; i++)); do
+    cat <<EOF
+        ${i}: b_read_output = b_read_output_${i};
+EOF
+    done
+
+    cat <<EOF
+        default: b_read_output = 32'hXXXXXXXX;
+        endcase
+    end
+endmodule
+EOF
+    exit 0
+elif [[ "$1" == "-s" ]]; then
+    open_output_file generate_hex_files.sh
+    chmod +x generate_hex_files.sh
+    cat <<EOF
+#!/bin/bash
+# Copyright 2018 Jacob Lifshay
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+mapfile -t words < <(hexdump -v -e '/4 "%08X\n"' < ram.bin)
+chunk_size=${chunk_size}
+chunk_count=${chunk_count}
+EOF
+    cat <<'EOF'
+if (( chunk_size * chunk_count != 4 * ${#words[@]} )); then
+    echo "ram.bin is the wrong size: expected $((chunk_size * chunk_count / 4)) words, got ${#words[@]}" >&2
+    exit 1
+fi
+word_index=0
+for((chunk=0;chunk<chunk_count;chunk++)); do
+    exec 3>"ram_${chunk}_byte0.hex" 4>"ram_${chunk}_byte1.hex" 5>"ram_${chunk}_byte2.hex" 6>"ram_${chunk}_byte3.hex"
+    for((i=0;i<chunk_size;i+=4)); do
+        word="${words[word_index++]}"
+        echo "${word:6:2}" >&3
+        echo "${word:4:2}" >&4
+        echo "${word:2:2}" >&5
+        echo "${word:0:2}" >&6
+    done
+done
+exit 0
+EOF
+else
+    error $'unknown option\nusage: '"$0"$' [-v|-s]\n-v\tgenerate block_memory.v\n-s\tgenerate generate_hex_files.sh'
+fi
+
diff --git a/software/ram.ld b/software/ram.ld
new file mode 100644 (file)
index 0000000..1d9910a
--- /dev/null
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+SECTIONS
+{
+    . = 0x10000;
+    .ram : { 
+        *(.startup)
+        *(.text*)
+        __global_pointer$ = . + 0x800;
+        *(.sdata*)
+        *(.sbss*)
+        *(.data*)
+        *(.rodata*)
+        *(.bss*)
+    }
+    /DISCARD/ : {
+        *(.comment)
+    }
+}
diff --git a/software/start.cpp b/software/start.cpp
new file mode 100644 (file)
index 0000000..4ef088e
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <cstdint>
+
+int main(int argc, char **argv);
+
+extern "C" void _start() noexcept
+{
+    static char arg0[] = "";
+    static char *argv[2] = {arg0, nullptr};
+    main(1, argv);
+    while(true)
+    {
+        asm("wfi");
+    }
+}
+
diff --git a/software/startup.S b/software/startup.S
new file mode 100644 (file)
index 0000000..a230e2a
--- /dev/null
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+.global _start
+.section .startup
+.option push
+.option norelax
+.reset:
+la gp, __global_pointer$
+li sp, 0x18000
+.option pop
+j _start
+.balign 0x40
+.trap:
+j .trap
diff --git a/text_initial.hex b/text_initial.hex
new file mode 100644 (file)
index 0000000..b502e1e
--- /dev/null
@@ -0,0 +1,128 @@
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
+FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF FF
diff --git a/vga.v b/vga.v
new file mode 100644 (file)
index 0000000..03d0624
--- /dev/null
+++ b/vga.v
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module vga(
+    input clk,
+       output [7:0] vga_r,
+       output [7:0] vga_g,
+       output [7:0] vga_b,
+       output vga_hsync,
+       output vga_vsync,
+    output vga_blank,
+    output vga_pixel_clock,
+    input tty_write,
+    input [7:0] tty_data,
+    output tty_busy
+    );
+       
+    wire pixel_clock;
+    
+    vga_clock_generator clock_generator(clk, pixel_clock);
+    
+    wire location_generator_hsync;
+    wire location_generator_vsync;
+    wire location_generator_blank;
+    wire [15:0] location_generator_x;
+    wire [15:0] location_generator_y;
+    wire location_generator_xy_in_active;
+    
+    vga_location_generator location_generator(pixel_clock,
+        location_generator_hsync,
+        location_generator_vsync,
+        location_generator_blank,
+        location_generator_x,
+        location_generator_y,
+        location_generator_xy_in_active);
+        
+    wire [7:0] text_buffer_screen_char;
+    reg text_buffer_hsync;
+    reg text_buffer_vsync;
+    reg text_buffer_blank;
+    reg [15:0] text_buffer_x;
+    reg [15:0] text_buffer_y;
+    reg text_buffer_xy_in_active;
+    
+    initial text_buffer_hsync = 0;
+    initial text_buffer_vsync = 0;
+    initial text_buffer_blank = 0;
+    initial text_buffer_x = 0;
+    initial text_buffer_y = 0;
+    initial text_buffer_xy_in_active = 0;
+    
+    always @(posedge pixel_clock) text_buffer_hsync <= location_generator_hsync;
+    always @(posedge pixel_clock) text_buffer_vsync <= location_generator_vsync;
+    always @(posedge pixel_clock) text_buffer_blank <= location_generator_blank;
+    always @(posedge pixel_clock) text_buffer_x <= location_generator_x;
+    always @(posedge pixel_clock) text_buffer_y <= location_generator_y;
+    always @(posedge pixel_clock) text_buffer_xy_in_active <= location_generator_xy_in_active;
+        
+    vga_text_buffer text_buffer(pixel_clock,
+        location_generator_x,
+        location_generator_y,
+        location_generator_xy_in_active,
+        text_buffer_screen_char,
+        clk,
+        tty_write,
+        tty_data,
+        tty_busy);
+        
+    wire [7:0] font_generator_r;
+    wire [7:0] font_generator_g;
+    wire [7:0] font_generator_b;
+        
+    vga_font_generator font_generator(
+        pixel_clock,
+        text_buffer_x,
+        text_buffer_y,
+        text_buffer_xy_in_active,
+        text_buffer_screen_char,
+        font_generator_r,
+        font_generator_g,
+        font_generator_b);
+
+    reg font_generator_hsync;
+    reg font_generator_vsync;
+    reg font_generator_blank;
+    
+    initial font_generator_hsync = 0;
+    initial font_generator_vsync = 0;
+    initial font_generator_blank = 0;
+    
+    always @(posedge pixel_clock) font_generator_hsync <= text_buffer_hsync;
+    always @(posedge pixel_clock) font_generator_vsync <= text_buffer_vsync;
+    always @(posedge pixel_clock) font_generator_blank <= text_buffer_blank;
+    
+    assign vga_pixel_clock = ~pixel_clock;
+    
+    reg output_hsync;
+    reg output_vsync;
+    reg output_blank;
+    reg [7:0] output_r;
+    reg [7:0] output_g;
+    reg [7:0] output_b;
+    
+    initial output_hsync = 0;
+    initial output_vsync = 0;
+    initial output_blank = 0;
+    initial output_r = 0;
+    initial output_g = 0;
+    initial output_b = 0;
+    
+    always @(posedge pixel_clock) output_hsync = font_generator_hsync;
+    always @(posedge pixel_clock) output_vsync = font_generator_vsync;
+    always @(posedge pixel_clock) output_blank = font_generator_blank;
+    always @(posedge pixel_clock) output_r = font_generator_r;
+    always @(posedge pixel_clock) output_g = font_generator_g;
+    always @(posedge pixel_clock) output_b = font_generator_b;
+
+       assign vga_r = output_r;
+       assign vga_g = output_g;
+       assign vga_b = output_b;
+    
+       reg final_hsync;
+       reg final_vsync;
+    reg final_blank;
+    
+    initial final_hsync = 0;
+    initial final_vsync = 0;
+    initial final_blank = 0;
+    
+    always @(posedge pixel_clock) final_hsync = output_hsync;
+    always @(posedge pixel_clock) final_vsync = output_vsync;
+    always @(posedge pixel_clock) final_blank = font_generator_blank;
+    
+    assign vga_hsync = final_hsync;
+    assign vga_vsync = final_vsync;
+    assign vga_blank = font_generator_blank;
+endmodule
diff --git a/vga_clock_generator.v b/vga_clock_generator.v
new file mode 100644 (file)
index 0000000..3cf495e
--- /dev/null
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module vga_clock_generator(
+    input clk,
+    output pixel_clock
+    );
+       
+    assign pixel_clock = clk;
+endmodule
diff --git a/vga_font_generator.v b/vga_font_generator.v
new file mode 100644 (file)
index 0000000..cafed4e
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module vga_font_generator(
+       input pixel_clock,
+    input [15:0] screen_x,
+    input [15:0] screen_y,
+    input screen_valid,
+    input [7:0] screen_char,
+       output [7:0] vga_r,
+       output [7:0] vga_g,
+       output [7:0] vga_b
+    );
+    
+    parameter font_x_size = 8;
+    parameter font_y_size = 8;
+       
+    // ram_style = "block"
+    reg [font_x_size - 1 : 0] font8x8[0 : 256 * font_y_size - 1];
+    
+    initial $readmemh("font8x8.hex", font8x8);
+    
+    wire [2:0] sub_char_x = screen_x[2:0];
+    wire [2:0] sub_char_y = screen_y[2:0];
+    wire [15:0] font_address = {screen_char, sub_char_y};
+    reg [7:0] font_line;
+    reg [2:0] output_sub_char_x;
+
+    initial font_line = 0;
+    initial output_sub_char_x = 0;
+    
+    always @(posedge pixel_clock) begin
+        font_line <= font8x8[font_address];
+        output_sub_char_x <= sub_char_x;
+    end
+    
+    wire pixel_active = ((font_line >> output_sub_char_x) & 1) == 1;
+    assign vga_r = pixel_active ? 255 : 0;
+    assign vga_g = pixel_active ? 255 : 0;
+    assign vga_b = pixel_active ? 255 : 0;
+    
+endmodule
diff --git a/vga_location_generator.v b/vga_location_generator.v
new file mode 100644 (file)
index 0000000..5a380cf
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module vga_location_generator(
+    input pixel_clock,
+       output reg hsync,
+       output reg vsync,
+    output reg blank,
+    output reg [15:0] x,
+    output reg [15:0] y,
+    output reg xy_in_active
+    );
+       
+       parameter x_front_porch = 56;
+       parameter x_active = 800;
+       parameter x_back_porch = 64;
+       parameter x_sync = 120;
+       parameter y_front_porch = 37;
+       parameter y_active = 600;
+       parameter y_back_porch = 23;
+       parameter y_sync = 6;
+        
+    wire x_at_end = (x == x_active + x_back_porch + x_sync + x_front_porch);
+    wire y_at_end = (y == y_active + y_back_porch + y_sync + y_front_porch);
+    wire [15:0] next_x = x_at_end ? 0 : x + 1;
+    wire [15:0] next_y = x_at_end ? (y_at_end ? 0 : y + 1) : y;
+    wire next_xy_in_active = (next_x < x_active) & (next_y < y_active);
+
+    initial begin
+        hsync = 0;
+        vsync = 0;
+        blank = 0;
+        x = 0;
+        y = 0;
+    end
+
+       always @(posedge pixel_clock) begin
+               x <= next_x;
+        y <= next_y;
+        blank <= next_xy_in_active;
+        hsync <= ((x >= x_active + x_back_porch) & (x < x_active + x_back_porch + x_sync));
+        vsync <= ((y >= y_active + y_back_porch) & (y < y_active + y_back_porch + y_sync));
+        xy_in_active <= next_xy_in_active;
+       end
+endmodule
diff --git a/vga_text_buffer.v b/vga_text_buffer.v
new file mode 100644 (file)
index 0000000..4bf69f3
--- /dev/null
@@ -0,0 +1,280 @@
+/*
+ * Copyright 2018 Jacob Lifshay
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+`timescale 1ns / 100ps
+
+module vga_text_buffer(
+    input pixel_clock,
+    input [15:0] screen_x,
+    input [15:0] screen_y,
+    input screen_valid,
+    output reg [7:0] screen_char,
+    input clk,
+    input tty_write,
+    input [7:0] tty_data,
+    output reg tty_busy
+    );
+    
+    parameter font_x_size = 8;
+    parameter font_y_size = 8;
+    parameter screen_x_size = 800;
+    parameter screen_y_size = 600;
+    parameter text_x_size = screen_x_size / font_x_size;
+    parameter text_y_size = screen_y_size / font_y_size;
+    parameter ram_x_size = 128;
+    parameter ram_y_size = 128;
+    
+    // ram_style = "block"
+    reg [7:0] text_ram[ram_x_size * ram_y_size - 1 : 0];
+
+    initial $readmemh("text_initial.hex", text_ram);
+
+    initial tty_busy = 1;
+    
+    initial screen_char = 0;
+    
+    reg [11:0] scroll_amount;
+    
+    initial scroll_amount = 0;
+    
+    always @(posedge pixel_clock) begin
+        screen_char <= screen_valid ? text_ram[ram_x_size * ((screen_y / font_y_size) + scroll_amount) + (screen_x / font_x_size)] : 0;
+    end
+    
+    reg [11:0] cursor_x;
+    reg [11:0] cursor_y;
+    
+    initial cursor_x = 0;
+    initial cursor_y = 0;
+    
+    reg [2:0] state;
+    
+    initial state = 0;
+    
+    wire [11:0] cursor_x_after_tab_unwrapped = ((cursor_x >> 3) + 1) << 3;
+    wire [11:0] cursor_x_after_tab = (cursor_x_after_tab_unwrapped == text_x_size ? 0 : cursor_x_after_tab_unwrapped);
+    
+    reg [15:0] text_ram_write_address;
+    reg text_ram_write_enable;
+    reg [7:0] text_ram_write_data;
+    
+    always @(posedge clk) begin
+        if(text_ram_write_enable)
+            text_ram[text_ram_write_address] <= text_ram_write_data;
+    end
+    
+    parameter space_char = 'h20;
+    parameter escape_char = 'h1B;
+    parameter left_bracket_char = 'h5B;
+    parameter capital_H_char = 'h48;
+    
+    always @(posedge clk) begin
+        text_ram_write_enable = 0;
+        case(state)
+            0: begin
+                cursor_x <= 0;
+                cursor_y <= 0;
+                tty_busy <= 1;
+                state <= 1;
+                scroll_amount <= 0;
+            end
+            1: begin
+                if(cursor_x != ram_x_size - 1) begin
+                    tty_busy <= 1;
+                    text_ram_write_enable = 1;
+                    text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                    text_ram_write_data = space_char;
+                    cursor_x <= cursor_x + 1;
+                end
+                else if(cursor_y != ram_y_size - 1) begin
+                    tty_busy <= 1;
+                    text_ram_write_enable = 1;
+                    text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                    text_ram_write_data = space_char;
+                    cursor_x <= 0;
+                    cursor_y <= cursor_y + 1;
+                end
+                else begin
+                    text_ram_write_enable = 1;
+                    text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                    text_ram_write_data = space_char;
+                    tty_busy <= 0;
+                    state <= 2;
+                    cursor_x <= 0;
+                    cursor_y <= 0;
+                end
+            end
+            2: begin
+                if(tty_write) begin
+                    case (tty_data)
+                        'h0A: begin
+                            if(cursor_y != text_y_size - 1) begin
+                                cursor_x <= 0;
+                                cursor_y <= cursor_y + 1;
+                                tty_busy <= 0;
+                            end
+                            else begin
+                                cursor_x <= 0;
+                                tty_busy <= 1;
+                                state <= 3;
+                                scroll_amount <= scroll_amount + 1;
+                            end
+                        end
+                        'h1B: begin
+                            tty_busy <= 0;
+                            state <= 4;
+                        end
+                        'h0D: begin
+                            cursor_x <= 0;
+                            tty_busy <= 0;
+                        end
+                        'h09: begin
+                            cursor_x <= cursor_x_after_tab;
+                            tty_busy <= 0;
+                        end
+                        default: begin
+                            text_ram_write_enable = 1;
+                            text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                            text_ram_write_data = tty_data;
+                            if(cursor_x != text_x_size - 1) begin
+                                cursor_x <= cursor_x + 1;
+                                tty_busy <= 0;
+                            end
+                            else if(cursor_y != text_y_size - 1) begin
+                                cursor_x <= 0;
+                                cursor_y <= cursor_y + 1;
+                                tty_busy <= 0;
+                            end
+                            else begin
+                                cursor_x <= 0;
+                                cursor_y <= text_y_size - 1;
+                                tty_busy <= 1;
+                                state <= 3;
+                                scroll_amount <= scroll_amount + 1;
+                            end
+                        end
+                    endcase
+                end
+                else begin
+                    tty_busy <= 0;
+                end
+            end
+            3: begin
+                if(cursor_x != ram_x_size - 1) begin
+                    tty_busy <= 1;
+                    text_ram_write_enable = 1;
+                    text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                    text_ram_write_data = space_char;
+                    cursor_x <= cursor_x + 1;
+                end
+                else begin
+                    text_ram_write_enable = 1;
+                    text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                    text_ram_write_data = space_char;
+                    tty_busy <= 0;
+                    state <= 2;
+                    cursor_x <= 0;
+                end
+            end
+            4: begin
+                if(tty_write) begin
+                    case (tty_data)
+                        'h52: begin // "R": reset
+                            tty_busy <= 1;
+                            state <= 0;
+                        end
+                        left_bracket_char: begin
+                            tty_busy <= 0;
+                            state <= 5;
+                        end
+                        default: begin
+                            text_ram_write_enable = 1;
+                            text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                            text_ram_write_data = tty_data;
+                            if(cursor_x != text_x_size - 1) begin
+                                cursor_x <= cursor_x + 1;
+                                tty_busy <= 0;
+                                state <= 2;
+                            end
+                            else if(cursor_y != text_y_size - 1) begin
+                                cursor_x <= 0;
+                                cursor_y <= cursor_y + 1;
+                                tty_busy <= 0;
+                                state <= 2;
+                            end
+                            else begin
+                                cursor_x <= 0;
+                                cursor_y <= text_y_size - 1;
+                                tty_busy <= 1;
+                                state <= 3;
+                                scroll_amount <= scroll_amount + 1;
+                            end
+                        end
+                    endcase
+                end
+                else begin
+                    tty_busy <= 0;
+                end
+            end
+            5: begin
+                if(tty_write) begin
+                    case (tty_data)
+                        capital_H_char: begin // move to top left
+                            tty_busy <= 0;
+                            state <= 2;
+                            cursor_x <= 0;
+                            cursor_y <= 0;
+                        end
+                        default: begin
+                            text_ram_write_enable = 1;
+                            text_ram_write_address = ram_x_size * (cursor_y + scroll_amount) + cursor_x;
+                            text_ram_write_data = tty_data;
+                            if(cursor_x != text_x_size - 1) begin
+                                cursor_x <= cursor_x + 1;
+                                tty_busy <= 0;
+                                state <= 2;
+                            end
+                            else if(cursor_y != text_y_size - 1) begin
+                                cursor_x <= 0;
+                                cursor_y <= cursor_y + 1;
+                                tty_busy <= 0;
+                                state <= 2;
+                            end
+                            else begin
+                                cursor_x <= 0;
+                                cursor_y <= text_y_size - 1;
+                                tty_busy <= 1;
+                                state <= 3;
+                                scroll_amount <= scroll_amount + 1;
+                            end
+                        end
+                    endcase
+                end
+                else begin
+                    tty_busy <= 0;
+                end
+            end
+            default: state <= 0;
+        endcase
+    end
+
+endmodule