// Special version of femtosoc for mecrisp-quintus (Forth interpreter) on IceStick, by Matthias Koch // mecrisp website: http://mecrisp.sourceforge.net/ `default_nettype none // Makes it easier to detect typos ! `define NRV_MINIRV32 // Mini config, can execute code stored in SPI flash from 1Mb offset (mapped to address 0x800000) `define NRV_RUN_FROM_SPI_FLASH // Running code from the SPI flash (changes the constant for delay loops) `define NRV_RESET_ADDR 24'h810000 // Directly jump into mapped SPI Flash, `define NRV_COUNTER_WIDTH 32 // Number of bits in click counter `include "PROCESSOR/femtorv32_quark.v" // Minimalistic version of the processor `include "DEVICES/uart_picosoc_shrunk.v" `include "DEVICES/MappedSPIFlash.v" module femtosoc( input oscillator, output D1, D2, D3, D4, D5, output TXD, input RXD, output spi_clk, output spi_cs_n, inout spi_mosi, inout spi_miso, // input IR_RX, // output IR_TX, // output IR_SD, inout PIO1_02, // PMOD 1 inout PIO1_03, // PMOD 2 inout PIO1_04, // PMOD 3 inout PIO1_05, // PMOD 4 inout PIO1_06, // PMOD 5 inout PIO1_07, // PMOD 6 inout PIO1_08, // PMOD 7 inout PIO1_09, // PMOD 8 inout PIO0_02, // Header 1 inout PIO0_03, // Header 2 inout PIO0_04, // Header 3 inout PIO0_05, // Header 4 inout PIO0_06, // Header 5 inout PIO0_07, // Header 6 inout PIO0_08, // Header 7 inout PIO0_09, // Header 8 inout PIO2_10, // Header 1 inout PIO2_11, // Header 2 inout PIO2_12, // Header 3 inout PIO2_13, // Header 4 inout PIO2_14, // Header 5 inout PIO2_15, // Header 6 inout PIO2_16, // Header 7 inout PIO2_17, // Header 8 input reset_button ); // ###### Clock ######################################### wire clk; // Configured for 48 MHz SB_PLL40_CORE #(.FEEDBACK_PATH("SIMPLE"), .PLLOUT_SELECT("GENCLK"), .DIVR(4'b0000), .DIVF(7'b0111111), .DIVQ(3'b100), .FILTER_RANGE(3'b001), ) uut ( .REFERENCECLK(oscillator), .PLLOUTCORE(clk), .RESETB(1'b1), .BYPASS(1'b0) ); // ###### Reset logic ################################### reg [7:0] reset_cnt = 0; wire resetq = &reset_cnt; always @(posedge clk, negedge reset_button) begin if (!reset_button) reset_cnt <= 0; else reset_cnt <= reset_cnt + !resetq; end // ###### Cycle counter ################################# //reg [31:0] cycles; //always @(posedge clk) cycles <= cycles + 1; // ###### LEDS ########################################## reg [4:0] LEDs; assign {D5,D4,D3,D2,D1} = LEDs; // ###### RING OSCILLATOR ############################### wire [1:0] buffers_in, buffers_out; assign buffers_in = {buffers_out[0:0], ~buffers_out[1]}; SB_LUT4 #( .LUT_INIT(16'd2) ) buffers [1:0] ( .O(buffers_out), .I0(buffers_in), .I1(1'b0), .I2(1'b0), .I3(1'b0) ); wire random = ~buffers_out[1]; // ###### GPIO ########################################## wire [24:0] port_in; reg [23:0] port_out; reg [23:0] port_dir; assign port_in[24] = random; // PMOD SB_IO #(.PIN_TYPE(6'b1010_01)) fio0 (.PACKAGE_PIN(PIO1_02), .D_OUT_0(port_out[ 0]), .D_IN_0(port_in[ 0]), .OUTPUT_ENABLE(port_dir[ 0])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio1 (.PACKAGE_PIN(PIO1_03), .D_OUT_0(port_out[ 1]), .D_IN_0(port_in[ 1]), .OUTPUT_ENABLE(port_dir[ 1])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio2 (.PACKAGE_PIN(PIO1_04), .D_OUT_0(port_out[ 2]), .D_IN_0(port_in[ 2]), .OUTPUT_ENABLE(port_dir[ 2])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio3 (.PACKAGE_PIN(PIO1_05), .D_OUT_0(port_out[ 3]), .D_IN_0(port_in[ 3]), .OUTPUT_ENABLE(port_dir[ 3])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio4 (.PACKAGE_PIN(PIO1_06), .D_OUT_0(port_out[ 4]), .D_IN_0(port_in[ 4]), .OUTPUT_ENABLE(port_dir[ 4])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio5 (.PACKAGE_PIN(PIO1_07), .D_OUT_0(port_out[ 5]), .D_IN_0(port_in[ 5]), .OUTPUT_ENABLE(port_dir[ 5])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio6 (.PACKAGE_PIN(PIO1_08), .D_OUT_0(port_out[ 6]), .D_IN_0(port_in[ 6]), .OUTPUT_ENABLE(port_dir[ 6])); SB_IO #(.PIN_TYPE(6'b1010_01)) fio7 (.PACKAGE_PIN(PIO1_09), .D_OUT_0(port_out[ 7]), .D_IN_0(port_in[ 7]), .OUTPUT_ENABLE(port_dir[ 7])); // Header 1 SB_IO #(.PIN_TYPE(6'b1010_01)) gio0 (.PACKAGE_PIN(PIO0_02), .D_OUT_0(port_out[ 8]), .D_IN_0(port_in[ 8]), .OUTPUT_ENABLE(port_dir[ 8])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio1 (.PACKAGE_PIN(PIO0_03), .D_OUT_0(port_out[ 9]), .D_IN_0(port_in[ 9]), .OUTPUT_ENABLE(port_dir[ 9])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio2 (.PACKAGE_PIN(PIO0_04), .D_OUT_0(port_out[10]), .D_IN_0(port_in[10]), .OUTPUT_ENABLE(port_dir[10])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio3 (.PACKAGE_PIN(PIO0_05), .D_OUT_0(port_out[11]), .D_IN_0(port_in[11]), .OUTPUT_ENABLE(port_dir[11])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio4 (.PACKAGE_PIN(PIO0_06), .D_OUT_0(port_out[12]), .D_IN_0(port_in[12]), .OUTPUT_ENABLE(port_dir[12])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio5 (.PACKAGE_PIN(PIO0_07), .D_OUT_0(port_out[13]), .D_IN_0(port_in[13]), .OUTPUT_ENABLE(port_dir[13])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio6 (.PACKAGE_PIN(PIO0_08), .D_OUT_0(port_out[14]), .D_IN_0(port_in[14]), .OUTPUT_ENABLE(port_dir[14])); SB_IO #(.PIN_TYPE(6'b1010_01)) gio7 (.PACKAGE_PIN(PIO0_09), .D_OUT_0(port_out[15]), .D_IN_0(port_in[15]), .OUTPUT_ENABLE(port_dir[15])); // Header 2 SB_IO #(.PIN_TYPE(6'b1010_01)) hio0 (.PACKAGE_PIN(PIO2_10), .D_OUT_0(port_out[16]), .D_IN_0(port_in[16]), .OUTPUT_ENABLE(port_dir[16])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio1 (.PACKAGE_PIN(PIO2_11), .D_OUT_0(port_out[17]), .D_IN_0(port_in[17]), .OUTPUT_ENABLE(port_dir[17])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio2 (.PACKAGE_PIN(PIO2_12), .D_OUT_0(port_out[18]), .D_IN_0(port_in[18]), .OUTPUT_ENABLE(port_dir[18])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio3 (.PACKAGE_PIN(PIO2_13), .D_OUT_0(port_out[19]), .D_IN_0(port_in[19]), .OUTPUT_ENABLE(port_dir[19])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio4 (.PACKAGE_PIN(PIO2_14), .D_OUT_0(port_out[20]), .D_IN_0(port_in[20]), .OUTPUT_ENABLE(port_dir[20])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio5 (.PACKAGE_PIN(PIO2_15), .D_OUT_0(port_out[21]), .D_IN_0(port_in[21]), .OUTPUT_ENABLE(port_dir[21])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio6 (.PACKAGE_PIN(PIO2_16), .D_OUT_0(port_out[22]), .D_IN_0(port_in[22]), .OUTPUT_ENABLE(port_dir[22])); SB_IO #(.PIN_TYPE(6'b1010_01)) hio7 (.PACKAGE_PIN(PIO2_17), .D_OUT_0(port_out[23]), .D_IN_0(port_in[23]), .OUTPUT_ENABLE(port_dir[23])); // ###### UART ########################################## wire serial_valid, serial_busy; wire [7:0] serial_data; wire serial_wr = io_wstrb & io_word_address[IO_UART_DAT_bit]; wire serial_rd = io_rstrb & io_word_address[IO_UART_DAT_bit]; buart #( .FREQ_MHZ(48), .BAUDS(115200) ) the_buart ( .clk(clk), .resetq(resetq), .rx(RXD), .tx(TXD), .rd(serial_rd), .wr(serial_wr), .valid(serial_valid), .busy(serial_busy), .tx_data(io_wdata[7:0]), .rx_data(serial_data) ); // ###### IO PORTS ###################################### // We got a total of 20 bits for 1-hot addressing of IO registers. localparam IO_LEDS_bit = 0; // RW four leds localparam IO_UART_DAT_bit = 1; // RW write: data to send (8 bits) read: received data (8 bits) localparam IO_UART_CNTL_bit = 2; // R status. bit 8: valid read data. bit 9: busy sending localparam IO_PORT_IN_bit = 3; // R: GPIO port in localparam IO_PORT_OUT_bit = 4; // RW: GPIO port out localparam IO_PORT_DIR_bit = 5; // RW: GPIO port dir // localparam IO_CYCLES_bit = 6; assign io_rdata = (io_word_address[IO_UART_DAT_bit ] ? {22'd0, serial_busy, serial_valid, serial_data} : 32'd0) | (io_word_address[IO_UART_CNTL_bit] ? {22'd0, serial_busy, serial_valid, serial_data} : 32'd0) | (io_word_address[IO_PORT_IN_bit] ? port_in : 32'd0) | (io_word_address[IO_PORT_OUT_bit] ? port_out : 32'd0) | (io_word_address[IO_PORT_DIR_bit] ? port_dir : 32'd0) | // (io_word_address[IO_CYCLES_bit] ? cycles : 32'd0) | (io_word_address[IO_LEDS_bit] ? LEDs : 32'd0); always @(posedge clk) begin if (io_wstrb && io_word_address[IO_LEDS_bit]) LEDs <= io_wdata; if (io_wstrb && io_word_address[IO_PORT_OUT_bit]) port_out <= io_wdata; if (io_wstrb && io_word_address[IO_PORT_DIR_bit]) port_dir <= io_wdata; end // For now, we got no device that has blocking reads or writes assign io_rbusy = 0 ; assign io_wbusy = 0 ; /*************************************************************************************************** /* * Memory and memory interface * memory map: * address[21:2] RAM word address (4 Mb max). * address[23:22] 00: RAM * 01: IO page (1-hot) (starts at 0x400000) * 10: SPI Flash page (starts at 0x800000) */ // The memory bus. wire [31:0] mem_address; // 24 bits are used internally. The two LSBs are ignored (using word addresses) wire [3:0] mem_wmask; // mem write mask and strobe /write Legal values are 000,0001,0010,0100,1000,0011,1100,1111 wire [31:0] mem_rdata; // processor <- (mem and peripherals) wire [31:0] mem_wdata; // processor -> (mem and peripherals) wire mem_rstrb; // mem read strobe. Goes high to initiate memory read. wire mem_rbusy; // processor <- (mem and peripherals). Stays high until a read transfer is finished. wire mem_wbusy; // processor <- (mem and peripherals). Stays high until a write transfer is finished. wire mem_wstrb = |mem_wmask; // mem write strobe, goes high to initiate memory write (deduced from wmask) // IO bus. wire mem_address_is_ram = (mem_address[23:22] == 2'b00); wire mem_address_is_io = (mem_address[23:22] == 2'b01); wire mem_address_is_spi_flash = (mem_address[23:22] == 2'b10); wire mapped_spi_flash_rbusy; wire [31:0] mapped_spi_flash_rdata; MappedSPIFlash mapped_spi_flash( .clk(clk), .rstrb(mem_rstrb && mem_address_is_spi_flash), .word_address(mem_address[21:2]), .rdata(mapped_spi_flash_rdata), .rbusy(mapped_spi_flash_rbusy), .CLK(spi_clk), .CS_N(spi_cs_n), .IO({spi_miso,spi_mosi}) ); wire [31:0] io_rdata; wire [31:0] io_wdata = mem_wdata; wire io_rstrb = mem_rstrb && mem_address_is_io; wire io_wstrb = mem_wstrb && mem_address_is_io; wire [19:0] io_word_address = mem_address[21:2]; // word offset in io page wire io_rbusy; wire io_wbusy; assign mem_rbusy = io_rbusy | mapped_spi_flash_rbusy ; assign mem_wbusy = io_wbusy; wire [19:0] ram_word_address = mem_address[21:2]; reg [31:0] RAM[(6144/4)-1:0]; reg [31:0] ram_rdata; always @(posedge clk) begin if(mem_address_is_ram) begin if(mem_wmask[0]) RAM[ram_word_address][ 7:0 ] <= mem_wdata[ 7:0 ]; if(mem_wmask[1]) RAM[ram_word_address][15:8 ] <= mem_wdata[15:8 ]; if(mem_wmask[2]) RAM[ram_word_address][23:16] <= mem_wdata[23:16]; if(mem_wmask[3]) RAM[ram_word_address][31:24] <= mem_wdata[31:24]; end ram_rdata <= RAM[ram_word_address]; end assign mem_rdata = mem_address_is_io ? io_rdata : mem_address_is_ram ? ram_rdata : mapped_spi_flash_rdata; /****************************************************************/ /* And last but not least, the processor */ FemtoRV32 #( .ADDR_WIDTH(24) ) processor( .clk(clk), .mem_addr(mem_address), .mem_wdata(mem_wdata), .mem_wmask(mem_wmask), .mem_rdata(mem_rdata), .mem_rstrb(mem_rstrb), .mem_rbusy(mem_rbusy), .mem_wbusy(mem_wbusy), .reset(resetq) ); endmodule