From: Jacob Lifshay Date: Wed, 21 Mar 2018 01:19:21 +0000 (-0700) Subject: add licenses and readme X-Git-Url: https://git.libre-soc.org/?p=rv32.git;a=commitdiff_plain;h=0758a80be0c6fc5d9632ddc88ec32b0477ec2424 add licenses and readme --- 0758a80be0c6fc5d9632ddc88ec32b0477ec2424 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..20598f5 --- /dev/null +++ b/.gitignore @@ -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 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 index 0000000..bc472bb --- /dev/null +++ b/block_memory.v @@ -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 index 0000000..092d00a --- /dev/null +++ b/block_memory_16kbit.v @@ -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 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 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 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 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 index 0000000..ffd943b --- /dev/null +++ b/cpu_decoder.v @@ -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 index 0000000..0e1ed59 --- /dev/null +++ b/cpu_fetch_stage.v @@ -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 index 0000000..b299ec5 --- /dev/null +++ b/cpu_memory_interface.v @@ -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 index 0000000..401e7b1 --- /dev/null +++ b/font8x8.hex @@ -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 index 0000000..4e42e98 Binary files /dev/null and b/main.bit differ diff --git a/main.ucf b/main.ucf new file mode 100644 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 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 index 0000000..404b101 --- /dev/null +++ b/main_test.v @@ -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 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 index 0000000..4e8412b --- /dev/null +++ b/rv32.xise @@ -0,0 +1,428 @@ + + + +
+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/software/.clang-format b/software/.clang-format new file mode 100644 index 0000000..c65d7a3 --- /dev/null +++ b/software/.clang-format @@ -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 index 0000000..bab65d9 --- /dev/null +++ b/software/.gitignore @@ -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 index 0000000..7b5ecce --- /dev/null +++ b/software/Makefile @@ -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 index 0000000..4c13aa0 --- /dev/null +++ b/software/main.cpp @@ -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 +#include + +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(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(0x80000010); +#endif +} + +inline void write_gpio(std::uint32_t value) +{ +#ifndef EMULATE_TARGET + *reinterpret_cast(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 +struct get_double_length_type; + +template <> +struct get_double_length_type +{ + typedef std::uint16_t type; +}; + +template <> +struct get_double_length_type +{ + typedef std::uint32_t type; +}; + +template <> +struct get_double_length_type +{ + typedef std::uint64_t type; +}; + +template <> +struct get_double_length_type +{ + typedef std::int16_t type; +}; + +template <> +struct get_double_length_type +{ + typedef std::int32_t type; +}; + +template <> +struct get_double_length_type +{ + typedef std::int64_t type; +}; + +template +constexpr T bidirectional_shift_left(T value, int amount) noexcept +{ + int max_shift = std::numeric_limits::digits; + if(amount <= -max_shift) + return value < 0 ? -1 : 0; + if(amount < 0) + return value >> -amount; + return value << amount; +} + +template +constexpr T bidirectional_shift_right(T value, int amount) noexcept +{ + return bidirectional_shift_left(value, -amount); +} + +template +class Fixed +{ +public: + typedef T underlying_type; + typedef typename get_double_length_type::type double_length_type; + static constexpr std::size_t total_bits = std::numeric_limits::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(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(v) << fractional_bits) + { + } + constexpr Fixed(short v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(int v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(long v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(long long v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(unsigned char v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(char v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(unsigned short v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(unsigned v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(unsigned long v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(unsigned long long v) noexcept : value(static_cast(v) << fractional_bits) + { + } + constexpr Fixed(float v) noexcept + : value(static_cast(static_cast(1ULL << fractional_bits) * v)) + { + } + constexpr Fixed(double v) noexcept + : value(static_cast(static_cast(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(a.value) * b.value >> fractional_bits); + } + friend constexpr Fixed operator/(Fixed a, Fixed b) noexcept + { + return make((static_cast(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(fractional_bits); + bit_index--) + { + Fixed new_guess = guess + make(static_cast(1) << (bit_index + fractional_bits)); + double_length_type new_guess_squared = guess_squared; + new_guess_squared += bidirectional_shift_left( + static_cast(guess.value), bit_index + 1); + new_guess_squared += bidirectional_shift_left( + static_cast(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(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(x); + x += 0.25; + return constexpr_sin2pi(x); +} + +template +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 +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> rotate(Vec2D> 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> ray_start_position; + Vec2D> ray_direction; + Vec2D current_position; + Fixed<> current_t; + Vec2D> next_t; + Vec2D> step_t; + Vec2D delta_position; + int last_hit_dimension = -1; + constexpr RayCaster(Vec2D> ray_start_position, Vec2D> 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> 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> forward(0, 0.05); + forward = rotate(forward, view_angle); + auto new_view_position = view_position + forward; + Vec2D 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> 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(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 index 0000000..4103268 --- /dev/null +++ b/software/make_block_memory.sh @@ -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<&2 + exit 1 +fi +word_index=0 +for((chunk=0;chunk"ram_${chunk}_byte0.hex" 4>"ram_${chunk}_byte1.hex" 5>"ram_${chunk}_byte2.hex" 6>"ram_${chunk}_byte3.hex" + for((i=0;i&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 index 0000000..1d9910a --- /dev/null +++ b/software/ram.ld @@ -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 index 0000000..4ef088e --- /dev/null +++ b/software/start.cpp @@ -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 + +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 index 0000000..a230e2a --- /dev/null +++ b/software/startup.S @@ -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 index 0000000..b502e1e --- /dev/null +++ b/text_initial.hex @@ -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 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 index 0000000..3cf495e --- /dev/null +++ b/vga_clock_generator.v @@ -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 index 0000000..cafed4e --- /dev/null +++ b/vga_font_generator.v @@ -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 index 0000000..5a380cf --- /dev/null +++ b/vga_location_generator.v @@ -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 index 0000000..4bf69f3 --- /dev/null +++ b/vga_text_buffer.v @@ -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