From 0758a80be0c6fc5d9632ddc88ec32b0477ec2424 Mon Sep 17 00:00:00 2001 From: Jacob Lifshay Date: Tue, 20 Mar 2018 18:19:21 -0700 Subject: [PATCH] add licenses and readme --- .gitignore | 77 ++++ ReadMe.md | 64 +++ block_memory.v | 270 ++++++++++++ block_memory_16kbit.v | 57 +++ cpu.bmm | 34 ++ cpu.v | 771 +++++++++++++++++++++++++++++++++ cpu.vh | 58 +++ cpu_alu.v | 80 ++++ cpu_decoder.v | 254 +++++++++++ cpu_fetch_stage.v | 104 +++++ cpu_memory_interface.v | 181 ++++++++ font8x8.hex | 256 +++++++++++ main.bit | Bin 0 -> 464286 bytes main.ucf | 94 +++++ main.v | 79 ++++ main_test.v | 71 ++++ riscv.vh | 175 ++++++++ rv32.xise | 428 +++++++++++++++++++ software/.clang-format | 65 +++ software/.gitignore | 8 + software/Makefile | 55 +++ software/main.cpp | 772 ++++++++++++++++++++++++++++++++++ software/make_block_memory.sh | 198 +++++++++ software/ram.ld | 39 ++ software/start.cpp | 37 ++ software/startup.S | 34 ++ text_initial.hex | 128 ++++++ vga.v | 158 +++++++ vga_clock_generator.v | 31 ++ vga_font_generator.v | 63 +++ vga_location_generator.v | 66 +++ vga_text_buffer.v | 280 ++++++++++++ 32 files changed, 4987 insertions(+) create mode 100644 .gitignore create mode 100644 ReadMe.md create mode 100644 block_memory.v create mode 100644 block_memory_16kbit.v create mode 100644 cpu.bmm create mode 100644 cpu.v create mode 100644 cpu.vh create mode 100644 cpu_alu.v create mode 100644 cpu_decoder.v create mode 100644 cpu_fetch_stage.v create mode 100644 cpu_memory_interface.v create mode 100644 font8x8.hex create mode 100644 main.bit create mode 100644 main.ucf create mode 100644 main.v create mode 100644 main_test.v create mode 100644 riscv.vh create mode 100644 rv32.xise create mode 100644 software/.clang-format create mode 100644 software/.gitignore create mode 100644 software/Makefile create mode 100644 software/main.cpp create mode 100755 software/make_block_memory.sh create mode 100644 software/ram.ld create mode 100644 software/start.cpp create mode 100644 software/startup.S create mode 100644 text_initial.hex create mode 100644 vga.v create mode 100644 vga_clock_generator.v create mode 100644 vga_font_generator.v create mode 100644 vga_location_generator.v create mode 100644 vga_text_buffer.v 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 0000000000000000000000000000000000000000..4e42e98d7f792b2e3f905fcd75bb8299970333d6 GIT binary patch literal 464286 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�?ZGj9JL^Xe>gCf&&{e{pM*|I5(u; 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

ad8(EWKU-j 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 + + +

+ + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 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 -- 2.30.2