Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 1 | /* |
| 2 | * SPDX-FileCopyrightText: 2020 Efabless Corporation |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | * SPDX-License-Identifier: Apache-2.0 |
| 16 | */ |
| 17 | |
| 18 | // This include is relative to $CARAVEL_PATH (see Makefile) |
| 19 | #include <defs.h> |
| 20 | #include <stub.c> |
| 21 | |
| 22 | /* |
| 23 | IO Test: |
| 24 | - Configures MPRJ lower 8-IO pins as outputs |
| 25 | - Observes counter value through the MPRJ lower 8 IO pins (in the testbench) |
| 26 | */ |
| 27 | |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 28 | #define GPIO0_OE_WRITE_ADDR ((uint32_t*)0x33031000) |
| 29 | #define GPIO0_OE_SET_ADDR ((uint32_t*)0x33031004) |
| 30 | #define GPIO0_OE_CLEAR_ADDR ((uint32_t*)0x33031008) |
| 31 | #define GPIO0_OE_TOGGLE_ADDR ((uint32_t*)0x3303100C) |
| 32 | #define GPIO0_OUTPUT_WRITE_ADDR ((uint32_t*)0x33031010) |
| 33 | #define GPIO0_OUTPUT_SET_ADDR ((uint32_t*)0x33031014) |
| 34 | #define GPIO0_OUTPUT_CLEAR_ADDR ((uint32_t*)0x33031018) |
| 35 | #define GPIO0_OUTPUT_TOGGLE_ADDR ((uint32_t*)0x3303101C) |
| 36 | #define GPIO0_INPUT_ADDR ((uint32_t*)0x33031020) |
| 37 | #define GPIO1_OE_WRITE_ADDR ((uint32_t*)0x33032000) |
| 38 | #define GPIO1_OE_SET_ADDR ((uint32_t*)0x33032004) |
| 39 | #define GPIO1_OE_CLEAR_ADDR ((uint32_t*)0x33032008) |
| 40 | #define GPIO1_OE_TOGGLE_ADDR ((uint32_t*)0x3303200C) |
| 41 | #define GPIO1_OUTPUT_WRITE_ADDR ((uint32_t*)0x33032010) |
| 42 | #define GPIO1_OUTPUT_SET_ADDR ((uint32_t*)0x33032014) |
| 43 | #define GPIO1_OUTPUT_CLEAR_ADDR ((uint32_t*)0x33032018) |
| 44 | #define GPIO1_OUTPUT_TOGGLE_ADDR ((uint32_t*)0x3303201C) |
| 45 | #define GPIO1_INPUT_ADDR ((uint32_t*)0x33032020) |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 46 | |
| 47 | #define MPRJ_WB_ADDRESS (*(volatile uint32_t*)0x30000000) |
| 48 | #define MPRJ_WB_DATA_LOCATION 0x30008000 |
| 49 | |
| 50 | void wbWrite (uint32_t* location, uint32_t value) |
| 51 | { |
| 52 | // Write the address |
| 53 | uint32_t locationData = (uint32_t)location; |
| 54 | MPRJ_WB_ADDRESS = locationData & 0xFFFF8000; |
| 55 | |
| 56 | // Write the data |
| 57 | uint32_t writeAddress = (locationData & 0x00007FFF) | MPRJ_WB_DATA_LOCATION; |
| 58 | *((volatile uint32_t*)writeAddress) = value; |
| 59 | } |
| 60 | |
| 61 | uint32_t wbRead (uint32_t* location) |
| 62 | { |
| 63 | // Write the address |
| 64 | uint32_t locationData = (uint32_t)location; |
| 65 | MPRJ_WB_ADDRESS = locationData & 0xFFFF8000; |
| 66 | |
| 67 | // Write the data |
| 68 | uint32_t writeAddress = (locationData & 0x00007FFF) | MPRJ_WB_DATA_LOCATION; |
| 69 | return *((volatile uint32_t*)writeAddress); |
| 70 | } |
| 71 | |
| 72 | void nextTest (bool testPassing) |
| 73 | { |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 74 | uint32_t testPassingOutput = testPassing ? 0x01000 : 0; |
| 75 | wbWrite (GPIO0_OUTPUT_SET_ADDR, testPassingOutput | 0x02000); |
| 76 | wbWrite (GPIO0_OUTPUT_CLEAR_ADDR, 0x02000); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 77 | } |
| 78 | |
| 79 | void main () |
| 80 | { |
| 81 | /* |
| 82 | IO Control Registers |
| 83 | | DM | VTRIP | SLOW | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN | |
| 84 | | 3-bits | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | 1-bit | |
| 85 | |
| 86 | Output: 0000_0110_0000_1110 (0x1808) = GPIO_MODE_USER_STD_OUTPUT |
| 87 | | DM | VTRIP | SLOW | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN | |
| 88 | | 110 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | 0 | 0 | |
| 89 | |
| 90 | |
| 91 | Input: 0000_0001_0000_1111 (0x0402) = GPIO_MODE_USER_STD_INPUT_NOPULL |
| 92 | | DM | VTRIP | SLOW | AN_POL | AN_SEL | AN_EN | MOD_SEL | INP_DIS | HOLDH | OEB_N | MGMT_EN | |
| 93 | | 001 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | |
| 94 | |
| 95 | */ |
| 96 | |
| 97 | /* Set up the housekeeping SPI to be connected internally so */ |
| 98 | /* that external pin changes don't affect it. */ |
| 99 | |
| 100 | // Connect the housekeeping SPI to the SPI master |
| 101 | // so that the CSB line is not left floating. This allows |
| 102 | // all of the GPIO pins to be used for user functions. |
| 103 | |
| 104 | // https://github.com/efabless/caravel/blob/main/docs/other/gpio.txt |
| 105 | |
| 106 | // Enable the wishbone bus |
| 107 | reg_wb_enable = 1; |
| 108 | |
| 109 | // Enable GPIO |
| 110 | reg_mprj_io_12 = GPIO_MODE_USER_STD_OUTPUT; |
| 111 | reg_mprj_io_13 = GPIO_MODE_USER_STD_OUTPUT; |
| 112 | reg_mprj_io_14 = GPIO_MODE_USER_STD_OUTPUT; |
| 113 | reg_mprj_io_15 = GPIO_MODE_USER_STD_OUTPUT; |
| 114 | reg_mprj_io_16 = GPIO_MODE_USER_STD_OUTPUT; |
| 115 | reg_mprj_io_17 = GPIO_MODE_USER_STD_OUTPUT; |
| 116 | reg_mprj_io_18 = GPIO_MODE_USER_STD_INPUT_NOPULL; |
| 117 | reg_mprj_io_19 = GPIO_MODE_USER_STD_INPUT_NOPULL; |
| 118 | |
| 119 | /* Apply configuration */ |
| 120 | reg_mprj_xfer = 1; |
| 121 | while (reg_mprj_xfer == 1) {} |
| 122 | |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 123 | // Setup test output |
| 124 | bool testPass = true; |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 125 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, 0x01000); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 126 | |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 127 | wbWrite (GPIO0_OE_WRITE_ADDR, ~0x3F000); |
| 128 | wbWrite (GPIO0_OUTPUT_SET_ADDR, 0x04000); |
| 129 | wbWrite (GPIO0_OUTPUT_SET_ADDR, 0x08000); |
| 130 | wbWrite (GPIO0_OUTPUT_SET_ADDR, 0x10000); |
| 131 | wbWrite (GPIO0_OUTPUT_SET_ADDR, 0x20000); |
| 132 | wbWrite (GPIO0_OUTPUT_TOGGLE_ADDR, 0x3C000); |
| 133 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, 0x3C000); |
| 134 | wbWrite (GPIO0_OUTPUT_CLEAR_ADDR, 0x04000); |
| 135 | wbWrite (GPIO0_OUTPUT_CLEAR_ADDR, 0x08000); |
| 136 | wbWrite (GPIO0_OUTPUT_CLEAR_ADDR, 0x10000); |
| 137 | wbWrite (GPIO0_OUTPUT_CLEAR_ADDR, 0x20000); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 138 | nextTest (testPass); |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 139 | |
| 140 | wbWrite (GPIO1_OE_WRITE_ADDR, ~0x00000); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 141 | uint32_t ioData = wbRead (GPIO1_INPUT_ADDR); |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 142 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, (testPass ? 0x01000 : 0) | (ioData << 15)); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 143 | if (ioData != 0x2) testPass = false; // input = 2'b10 |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 144 | |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 145 | nextTest (testPass); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 146 | ioData = wbRead (GPIO1_INPUT_ADDR); |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 147 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, (testPass ? 0x01000 : 0) | (ioData << 15)); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 148 | if (ioData != 0x1) testPass = false; // input = 2'b01 |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 149 | |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 150 | nextTest (testPass); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 151 | ioData = wbRead (GPIO1_INPUT_ADDR); |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 152 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, (testPass ? 0x01000 : 0) | (ioData << 15)); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 153 | if (ioData != 0x3) testPass = false; // input = 2'b11 |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 154 | |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 155 | nextTest (testPass); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 156 | ioData = wbRead (GPIO1_INPUT_ADDR); |
Charlie | 7e13152 | 2022-05-24 23:56:27 +0100 | [diff] [blame] | 157 | wbWrite (GPIO0_OUTPUT_WRITE_ADDR, (testPass ? 0x01000 : 0) | (ioData << 15)); |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 158 | if (ioData != 0) testPass = false; // input = 2'b00 |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 159 | |
| 160 | // Finish test |
Charlie | e312600 | 2022-05-21 18:51:44 +0100 | [diff] [blame] | 161 | nextTest (testPass); |
Charlie | 7d7207a | 2022-05-21 18:43:37 +0100 | [diff] [blame] | 162 | } |