├── .gitattributes ├── .gitignore ├── README.md ├── app ├── assemble ├── core │ └── bootloader.ucisc ├── lib │ ├── 14seg.ucisc │ ├── arrays.ucisc │ ├── i2c.ucisc │ ├── mem_copy.ucisc │ ├── numbers.ucisc │ ├── string_serial.ucisc │ └── strings.ucisc └── test │ ├── 0_register_test.ucisc │ ├── 1_math_test.ucisc │ ├── 2_gpio_test.ucisc │ ├── 3_i2c_test.ucisc │ └── test_framework.ucisc ├── config └── checkstyle │ └── checkstyle.xml ├── docs ├── Overview.md ├── history │ ├── 1_Beginnings.md │ ├── 2_Transparent_Computing.md │ └── 3_Rough_Hardware_Outline.md └── programming_guide │ ├── 1.0_Getting_Started.md │ ├── 1.1_Configuring_IntelliJ.md │ ├── 1.2_Configuring_VIM.md │ ├── 2.0_Program_With_uCISC.md │ ├── 2.1_Accessing_Devices.md │ ├── 2.2.0_Common_Devices.md │ ├── 2.2.1_GPIO_Devices.md │ ├── 2.2.2_I2C_Devices.md │ ├── 2.2.3_Block_Memory_Devices.md │ ├── 2.2.4_UART_Devices.md │ ├── 3_Syntax_Quick_Reference.md │ ├── 5_Instruction_Set_Details.md │ └── images │ ├── intellij_uCISC_File_Type_Settings.png │ ├── syntax_highlighted_code.png │ └── vim_syntax_highlighting.png ├── examples ├── 00_register_push.ucisc ├── 01_register_imm.ucisc ├── 02_register_pop.ucisc ├── 03_complex_push.ucisc ├── 04_alu.ucisc ├── aoc │ └── 2020 │ │ ├── day_1.ucisc │ │ ├── day_2a.ucisc │ │ ├── day_2b.ucisc │ │ ├── day_3.ucisc │ │ ├── day_4a.ucisc │ │ ├── day_4b.ucisc │ │ ├── day_5a.ucisc │ │ ├── day_5b.ucisc │ │ └── day_6a.ucisc ├── blink.ucisc ├── factorial.ucisc ├── fib.ucisc ├── hello_world.ucisc ├── knight.ucisc ├── resources │ └── default-text.txt ├── space.ucisc ├── uart_echo.ucisc ├── uart_hello_world.ucisc └── uart_screen_echo.ucisc ├── extras └── ucisc.vim ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── hardware ├── 00_uCISC │ └── src │ │ ├── ecp5 │ │ └── pll.v │ │ ├── ice40 │ │ └── pll.v │ │ └── processor │ │ ├── alu.v │ │ ├── basic_memory_block.v │ │ ├── cpu.v │ │ ├── devices.v │ │ ├── dff.v │ │ ├── effect_decoder.v │ │ ├── gpio_device.v │ │ ├── graphics_mem.v_old │ │ ├── graphics_memory.v │ │ ├── graphics_modes.v │ │ ├── i2c_device.v │ │ ├── memory_block.v │ │ ├── parallel_buffer.v │ │ ├── spi_flash_device.v │ │ ├── uart_device.v │ │ ├── uart_rx.v │ │ └── uart_tx.v ├── 01_GK110 │ ├── ECP5 │ │ ├── Makefile │ │ ├── README.md │ │ ├── build.gradle │ │ ├── ecp5_5g_eval.lpf │ │ ├── ecp5_reference.json │ │ ├── ecp5_reference.svf │ │ ├── ecp5_reference_out.config │ │ ├── prog.hex │ │ ├── prog.hex.a.hex │ │ ├── prog.hex.b.hex │ │ ├── run_tests │ │ └── top.v │ ├── ICE40 │ │ ├── Makefile │ │ ├── pins.pcf │ │ ├── prog.hex │ │ ├── prog.hex.a.hex │ │ ├── prog.hex.b.hex │ │ ├── run_tests │ │ ├── top.bin │ │ └── top.v │ └── src │ │ ├── bootloader │ │ └── load.ucisc │ │ ├── gk110 │ │ └── gk110.v │ │ └── processor_old │ │ ├── alu.v │ │ ├── cpu.v │ │ ├── devices.v │ │ ├── dff.v │ │ ├── effect_decoder.v │ │ ├── gpio_device.v │ │ ├── graphics_mem.v_old │ │ ├── graphics_memory.v │ │ ├── graphics_modes.v │ │ ├── i2c_device.v │ │ ├── memory_block.v │ │ ├── parallel_buffer.v │ │ ├── uart_device.v │ │ ├── uart_rx.v │ │ └── uart_tx.v ├── ecp5_reference │ ├── Makefile │ ├── README.md │ ├── build.gradle │ ├── ecp5_5g_eval.lpf │ ├── ecp5_reference.json │ ├── ecp5_reference.svf │ ├── ecp5_reference_out.config │ ├── prog.hex │ ├── prog.hex.a.hex │ ├── prog.hex.b.hex │ ├── run_tests │ ├── src │ │ ├── alu.v │ │ ├── cpu.v │ │ ├── devices.v │ │ ├── dff.v │ │ ├── effect_decoder.v │ │ ├── graphics_mem.v_old │ │ ├── graphics_memory.v │ │ ├── graphics_modes.v │ │ ├── memory_block.v │ │ ├── parallel_buffer.v │ │ ├── pll.v │ │ ├── uart_device.v │ │ ├── uart_rx.v │ │ ├── uart_tx.v │ │ ├── vga.v │ │ └── vga_device.v │ ├── test │ │ ├── alu_tb.v │ │ ├── cpu_tb.v │ │ ├── defines.v │ │ ├── dff_tb.v │ │ ├── dff_tb.v.results │ │ ├── effect_decoder_tb.v │ │ ├── memory_block_tb.v │ │ ├── parallel_buffer_tb.v │ │ ├── test_prog.hex │ │ ├── test_prog.hex.a.hex │ │ ├── test_prog.hex.b.hex │ │ ├── test_prog.ucisc │ │ ├── uart_rx_tb.v │ │ └── uart_tx_tb.v │ └── top.v ├── ecp5_single_IPC │ ├── Makefile │ ├── alu.v │ ├── alu_decoder.v │ ├── copy_decoder.v │ ├── effect_decoder.v │ ├── instruction_decoder.v │ ├── memory_block.v │ ├── page_decoder.v │ ├── pc.v │ ├── processor_core.v │ └── register_block.v ├── grok80 │ ├── Makefile │ ├── README.md │ ├── pins.pcf │ ├── prog.hex │ ├── run_tests │ ├── src │ │ ├── alu.v │ │ ├── cpu.v │ │ ├── devices.v │ │ ├── dff.v │ │ ├── effect_decoder.v │ │ ├── memory_block.v │ │ ├── parallel_buffer.v │ │ ├── register_block.v │ │ ├── uart_device.v │ │ ├── uart_rx.v │ │ └── uart_tx.v │ ├── test │ │ ├── alu_tb.v │ │ ├── cpu_tb.v │ │ ├── defines.v │ │ ├── dff_tb.v │ │ ├── effect_decoder_tb.v │ │ ├── memory_block_tb.v │ │ ├── parallel_buffer_tb.v │ │ ├── test_prog.hex │ │ ├── test_prog.ucisc │ │ ├── uart_device_tb.v │ │ ├── uart_rx_tb.v │ │ └── uart_tx_tb.v │ └── top.v └── reference │ ├── Makefile │ ├── README.md │ ├── pins.pcf │ ├── prog.hex │ ├── run_tests │ ├── src │ ├── alu.v │ ├── cpu.v │ ├── devices.v │ ├── dff.v │ ├── effect_decoder.v │ ├── memory_block.v │ ├── parallel_buffer.v │ ├── uart_device.v │ ├── uart_rx.v │ └── uart_tx.v │ ├── test │ ├── alu_tb.v │ ├── cpu_tb.v │ ├── defines.v │ ├── dff_tb.v │ ├── effect_decoder_tb.v │ ├── memory_block_tb.v │ ├── parallel_buffer_tb.v │ ├── test_prog.hex │ ├── test_prog.ucisc │ ├── uart_device_tb.v │ ├── uart_rx_tb.v │ └── uart_tx_tb.v │ └── top.v ├── images └── uCISC_circuitverse.png ├── prog.hex ├── prog.hex.a.hex ├── prog.hex.b.hex ├── settings.gradle └── tools ├── build.gradle └── src ├── main └── java │ └── ucisc │ └── tools │ ├── Charset.java │ ├── GraphicsHexDump.java │ └── Utilities.java └── test └── java └── ucisc └── tools └── UtilitiesTest.java /.gitattributes: -------------------------------------------------------------------------------- 1 | # 2 | # https://help.github.com/articles/dealing-with-line-endings/ 3 | # 4 | # These are explicitly windows files and should use crlf 5 | *.bat text eol=crlf 6 | 7 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.swp 2 | *~ 3 | .byebug_history 4 | 5 | ucisc.json 6 | *.rpt 7 | *.blif 8 | *.asc 9 | *.bin 10 | test_bench 11 | .idea 12 | 13 | # Ignore Gradle project-specific cache directory 14 | .gradle 15 | 16 | # Ignore Gradle build output directory 17 | build 18 | 19 | # ucisc specific generated files 20 | video*.hex 21 | out 22 | compiled.hex 23 | compiled.bin 24 | 25 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | NOTE: I am in the middle of refactoring the project structure to support multiple 2 | CPU versions with different purposes. Also, I am moving the build system to 3 | gradle. Documentation coming soon. 4 | 5 | # Micro CISC (uCISC) 6 | 7 | uCISC is an opinionated micro instruction set, attempting to build a computer that 8 | is understandable by a single human from the CPU micro-architecture to the high 9 | level programming language. 10 | 11 | Quick link to the docs: [Overview](/docs/Overview.md) 12 | 13 | This is the main repo for uCISC development. This project will hold all the uCISC 14 | code developed for the instruction set, compiler, core libraries and OS. In addition 15 | to this project you will need an emulator or FPGA hardware to run the code. 16 | 17 | Virtual Execution: 18 | 19 | * [ucisc-kotlin](https://github.com/grokthis/ucisc-kotlin) - An emulator and debugger 20 | * OUTDATED - [ucisc-ruby](https://github.com/grokthis/ucisc-ruby) - A prototype compiler and VM 21 | written in ruby. 22 | 23 | ## Getting Started 24 | 25 | ### Install the Emulater 26 | 27 | See the [ucisc-kotlin](https://github.com/grokthis/ucisc-kotlin) readme for 28 | instructions on how to install the emulator. It is recommended to install it such 29 | that you have `ucisc` as a command on the terminal. 30 | 31 | ### Compiling and Running uCISC 32 | 33 | To compile uCISC code: 34 | 35 | ``` 36 | ucisc -c examples/fib.ucisc 37 | ``` 38 | 39 | To run uCISC code on the emulator 40 | 41 | ``` 42 | ucisc examples/knight.ucisc 43 | ``` 44 | 45 | If you need the UART port hooked up, you'll need to do a little more 46 | work. First, you'll need to create a virtual 2-way serial port. On linux you 47 | can do that with `socat` 48 | 49 | ``` 50 | > sudo apt install socat 51 | > socat -d -d pty,raw,echo=0 pty,raw,echo=0 52 | ``` 53 | This will print out something like: 54 | 55 | ``` 56 | 2020/11/30 19:06:28 socat[9758] N PTY is /dev/pts/4 57 | 2020/11/30 19:06:28 socat[9758] N PTY is /dev/pts/5 58 | 2020/11/30 19:06:28 socat[9758] N starting data transfer loop with FDs [5,5] and [7,7] 59 | ``` 60 | 61 | The two PTY devices are the two ends of your serial port. Hook one end to 62 | your serial application (I recommend GTKTerm) and the other to the uCISC 63 | emulator: 64 | 65 | ``` 66 | ucisc -r=/dev/pts/4 -t=/dev/pts/4 examples/space.ucisc 67 | ``` 68 | 69 | ### Running the Hardware 70 | 71 | You can find details about the reference implementation on the hardware in its 72 | own [README](hardware/README.md). 73 | 74 | ### Helpful Extras 75 | 76 | You will find helpful extras like syntax highlighting in the extras folder. At the 77 | moment we have a vim syntax setup. Feel free to send config files for other editors 78 | my way. 79 | 80 | ### Examples 81 | 82 | The examples folder contains standalone examples of ucisc code that you can run 83 | using the VM. 84 | 85 | ### Documentation 86 | 87 | You'll find helpful documentation in the docs directory. The documentation is 88 | constantly improving. Start at the [Introduction](/docs/Overview.md) for more 89 | information. 90 | 91 | -------------------------------------------------------------------------------- /app/assemble: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | if [ "$1" = "-h" ]; then 3 | echo "Assembles and installs uCISC code" 4 | echo "Usage:" 5 | echo " app/assemble [file1] [file2]" 6 | echo "" 7 | echo "The files are concatenated together and assembled." 8 | echo "If there is a compile error, the line number refers" 9 | echo "to the concatenated version. To echo the complete" 10 | echo "source with line numbers, use the '-n' option:" 11 | echo " app/assemble -n [file1] [file2]" 12 | echo "" 13 | exit 0 14 | fi 15 | 16 | if [ "$1" = "-n" ]; then 17 | cat "$@" 18 | exit 0 19 | fi 20 | 21 | echo "1. Assembling uCISC program..." 22 | 23 | ucisc -c "$@" > compiled.hex 24 | if [ "$?" = "0" ]; then 25 | echo " * uCISC program compiled" 26 | else 27 | echo " * Assembly error, aborting." 28 | exit 0 29 | fi 30 | 31 | echo "2. Writing binary file..." 32 | if [ -f "compiled.bin" ]; then 33 | rm compiled.bin 34 | fi 35 | 36 | set -e 37 | xxd -r -p compiled.hex compiled.bin 38 | 39 | echo " * uCISC binary created" 40 | echo "3. Programming flash..." 41 | tinyprog -u compiled.bin 42 | 43 | echo "Done." 44 | -------------------------------------------------------------------------------- /app/lib/arrays.ucisc: -------------------------------------------------------------------------------- 1 | # Arrays are lists of 16-bit values of some kind. 2 | # They are represented by a size, capacity and list of numbers. 3 | 4 | fun stack.createArray(address) { 5 | def array/r2 <- copy stack.address 6 | var array.size/0 7 | 8 | array.size <- copy val/0 9 | 10 | pc <- copy stack.return pop 11 | } 12 | 13 | # Adds a value to the stack, sets the flags if successful 14 | fun stack.pushToArray(address, value) { 15 | def array/r2 <- copy stack.address 16 | var array.size/0 17 | array.size <- add val/1 18 | 19 | def arrayPtr/r2 20 | var arrayPtr.value/0 21 | 22 | &arrayPtr <- add array.size 23 | arrayPtr.value <- copy stack.value 24 | 25 | pc <- copy stack.return pop 26 | } 27 | 28 | # Returns non-zero flag if array contains value 29 | fun stack.arrayContains(address, value) { 30 | def array/r2 <- copy stack.address 31 | var array.size/0 32 | var array.first/1 33 | 34 | def arrayPtr/r3 <- copy &array.first 35 | var arrayPtr.value/0 36 | 37 | var stack.count/0 push <- copy val/0 38 | { 39 | stack.count <~ sub array.size 40 | pc <0? copy stack.return pop 41 | 42 | arrayPtr.value <~ sub stack.value 43 | pc <0? copy pc/break 44 | 45 | stack.count <- add val/1 46 | &arrayPtr <- copy &arrayPtr/1 47 | 48 | pc <- copy pc/loop 49 | } 50 | 51 | # Set flags to non-zero, we found it! 52 | &arrayPtr <~ or val/1 53 | pc <- copy stack.return pop 54 | } 55 | -------------------------------------------------------------------------------- /app/lib/mem_copy.ucisc: -------------------------------------------------------------------------------- 1 | fun stack.copyDeviceBlock(fromAddress, fromDevice, toAddress, toDevice) { 2 | var stack.banking/0 push <- copy val/%70 3 | stack.fromDevice <~ add val/0 4 | stack.banking <|1 or val/2 5 | stack.toDevice <~ add val/0 6 | stack.banking <|1 or val/4 7 | 8 | banking <- copy stack.banking 9 | 10 | def a/r2 <- copy stack.fromAddress 11 | def b/r3 <- copy stack.toAddress 12 | 13 | var stack.i/0 push <- copy val/256 14 | { 15 | b <- copy a 16 | 17 | &a <- add val/1 18 | &b <- add val/1 19 | 20 | stack.i <- sub val/1 21 | pc <|1 copy pc/loop 22 | } 23 | 24 | banking <- copy val/%70 # set banking back to defaults 25 | pc <- copy stack.return pop 26 | } 27 | 28 | fun stack.copyBlock(fromAddress, toAddress) { 29 | stack.copyDeviceBlock(stack.fromAddress, val/0, stack.toAddress, val/0) 30 | pc <- copy stack.return pop 31 | } 32 | -------------------------------------------------------------------------------- /app/lib/numbers.ucisc: -------------------------------------------------------------------------------- 1 | fun stack.parseNumber(strAddr) -> number { 2 | def str/r2 <- copy stack.strAddr 3 | var str.char/0 4 | var stack.char/0 push <- copy val/0 5 | stack.number <- copy val/0 6 | { 7 | stack.char <- copy str.char 8 | stack.char <~ or val/0 9 | pc <0? copy pc/break 10 | 11 | stack.char <- sub val/48 # ASCII 0 12 | pc bcdValue 29 | 30 | # Print most significant digit 31 | var stack.temp/0 push <- copy stack.bcdValue 32 | stack.temp <- shr val/12 33 | { 34 | pc <0? copy pc/break 35 | 36 | stack.temp <- and val/15 37 | stack.printDigit(stack.temp, stack.serialDevice) 38 | } 39 | 40 | stack.temp <- copy stack.bcdValue 41 | stack.temp <- shr val/8 42 | { 43 | pc <0? copy pc/break 44 | 45 | stack.temp <- and val/15 46 | stack.printDigit(stack.temp, stack.serialDevice) 47 | } 48 | 49 | stack.temp <- copy stack.bcdValue 50 | stack.temp <- shr val/4 51 | { 52 | pc <0? copy pc/break 53 | 54 | stack.temp <- and val/15 55 | stack.printDigit(stack.temp, stack.serialDevice) 56 | } 57 | 58 | # Print least significant digit 59 | stack.temp <- copy stack.bcdValue 60 | stack.temp <- and val/15 61 | stack.printDigit(stack.temp, stack.serialDevice) 62 | 63 | pc <- copy stack.return pop 64 | 65 | fun stack.printDigit(value, serialDevice) { 66 | var stack.digit/0 push <- copy val/48 67 | stack.digit <- add stack.value 68 | 69 | stack.printChar(stack.digit, stack.serialDevice) 70 | 71 | pc <- copy stack.return pop 72 | } 73 | } 74 | 75 | # Converts 0 to 9999 to BCD from binary 76 | fun stack.toBCD(value) -> result { 77 | stack.result <- copy val/0 78 | # Thousands place 79 | { 80 | stack.value <- sub val/1000 81 | pc Today when I think back to the computers that I was most fond of, it wasn't the 39 | > Amiga. despite being much more powerful, the Amiga's operating system put a layer 40 | > between the hardware and the end user. 41 | > 42 | > I still have a fondness for the 8-bit computers, and I don't have a particular 43 | > favorite. I love writing code, and I'm just as happy to code on a VIC-20 a C64 or 44 | > a Plus4 as long as it has that same closeness to the hardware. 45 | > 46 | > The 8-Bit Guy 47 | 48 | Then I remembered the computer that I first learned on. I learned to program basic on 49 | a 1 line LCD readout and I LOVED it! Nostalgia Nerd has a great video about the 50 | [VTech computer toy line up](https://www.youtube.com/watch?v=9F4it_DH6ps) that brings 51 | back those memories in all their annoying PC speaker tonal glory. 52 | 53 | This is what I want to recapture in the uCISC homebrew computers I build, that 54 | close-to-the-hardware, transparent computer that rewards curiosity and discovery and 55 | leads you to a deeper understanding of how computers work. 56 | -------------------------------------------------------------------------------- /docs/programming_guide/1.1_Configuring_IntelliJ.md: -------------------------------------------------------------------------------- 1 | ## uCISC Programming Guide 2 | 3 | 1. [Getting Started](1.0_Getting_Started.md) 4 | 1. [Configuring IntelliJ](1.1_Configuring_IntelliJ.md) <-- you are here 5 | 2. [Configuring VIM](1.2_Configuring_VIM.md) 6 | 3. [Compiling uCISC Code](1.3_Compiling_uCISC_Code.md) 7 | 4. [Using the uCISC Simulator](1.4_Simulating_uCISC.md) 8 | 5. [Using the uCISC Soft Core](1.5_Running_uCISC_Soft_Core.md) 9 | 2. [Introduction to Programming With uCISC](2.0_Program_With_uCISC.md) 10 | 1. [Accessing External Devices](2.1_Accessing_Devices.md) 11 | 2. [Common Devices](2.2.0_Common_Devices.md) 12 | 1. [GPIO](2.2.1_GPIO_Devices.md) 13 | 2. [I2C](2.2.2_I2C_Devices.md) 14 | 3. [Block Memory](2.2.3_Block_Memory_Devices.md) 15 | 4. [UART](2.2.4_UART_Devices.md) 16 | 5. [Video Devices](2.2.5_Video_Devices.md) 17 | 3. [Advanced uCISC Programming Techniques](2.3_Advanced_Programming_Techniques.md) 18 | 3. [uCISC Syntax Quick Reference](3_Syntax_Quick_Reference.md) 19 | 4. [Standard Libraries](4_Standard_Libraries.md) 20 | 5. [Instruction Set Details](5_Instruction_Set_Details.md) 21 | 22 | ## Configuring IntelliJ for uCISC Development 23 | 24 | The main thing to do is create the syntax highlighting setup. 25 | 26 | 1. Go to File > Settings... > Editor > File Types 27 | 2. Under the "Recognized File Types" section, click the plus 28 | 3. Configure the following settings: 29 | 1. Name: uCISC 30 | 2. Description: uCISC Assembly 31 | 3. Line comment: # 32 | 4. Leave "Only at line start" unchecked 33 | 5. No block comment settings 34 | 6. Hex prefix: % 35 | 7. No number postfixes 36 | 8. Check "Support paired braces", "Support paired parens", "Support string escapes" 37 | 9. Leave "Support paired brackets" unchecked 38 | 10. Leave "Ignore case" unchecked 39 | 40 | ![IntelliJ File Type Screen Capture](images/intellij_uCISC_File_Type_Settings.png) 41 | 42 | 4. Paste the four sections of keywords from below into the for keyword tabs 43 | 5. Enable Ligatures (recommended) 44 | 1. File > Settings... > Editor > Font 45 | 2. Select "Enable ligatures" 46 | 3. Select a font that supports ligatures "JetBrains Mono" or "Fira Code" 47 | 48 | With dark mode on, your file should look something like this: 49 | 50 | ![Code Syntax Highlighting Example](images/syntax_highlighted_code.png) 51 | 52 | #### Section 1 Keywords 53 | 54 | ``` 55 | def 56 | fun 57 | public 58 | var 59 | ``` 60 | 61 | #### Section 2 Keywords 62 | 63 | ``` 64 | -> 65 | < 66 | -t= \ 11 | # examples/aoc/2020/day_3.ucisc \ 12 | # app/lib/numbers.ucisc \ 13 | # app/lib/string_serial.ucisc 14 | # 15 | 16 | def stack/r1 <- copy val/0 17 | 18 | var val.bufferStart/1024 19 | var val.bufferLen/65535 20 | var val.echoOn/0 21 | var val.serialDevice/32 22 | 23 | var val.patternWidth/31 24 | var val.lineWidth/32 25 | 26 | def buffer/r2 27 | var buffer.char/0 28 | 29 | var stack.x/0 push <- copy val/0 30 | var stack.y/0 push <- copy val/0 31 | var stack.offset/0 push <- copy val/0 32 | var stack.trees/0 push <- copy val/0 33 | var stack.parseStart/0 push <- copy val/0 34 | 35 | stack.readBuffer(val.bufferStart, val.bufferLen, val.echoOn, val.serialDevice) 36 | stack.parseStart <- copy val.bufferStart 37 | { 38 | stack.x <- add val/3 39 | stack.y <- add val/1 40 | 41 | { 42 | stack.x <~ sub val.patternWidth 43 | pc -t= \ 11 | # examples/aoc/2020/day_5a.ucisc \ 12 | # app/lib/numbers.ucisc \ 13 | # app/lib/string_serial.ucisc \ 14 | # app/lib/strings.ucisc 15 | 16 | def stack/r1 <- copy val/0 17 | 18 | var val.seatMap/1024 19 | var val.bufferStart/2048 20 | var val.bufferLen/32768 21 | var val.echoOn/0 22 | var val.serialDevice/32 23 | 24 | def str/r2 25 | var str.char/0 26 | 27 | def seatMap/r3 28 | var seatMap.occupied/0 29 | 30 | # User registers to copy buffer values, immediate is too small otherwise 31 | &r2 <- copy val.bufferLen 32 | &r3 <- copy val.bufferStart 33 | stack.readBuffer(&r3, &r2, val.echoOn, val.serialDevice) 34 | stack.printLine(pc/parsingData, val.serialDevice) 35 | 36 | &r2 <- copy val.bufferStart 37 | var stack.currentPos/0 push <- copy &r2 38 | { 39 | stack.findEndOfWhitespace(stack.currentPos) -> nextStart 40 | stack.currentPos <- copy stack.nextStart 41 | &r2 <- copy stack.nextStart pop 42 | 43 | &str <- copy stack.currentPos 44 | str.char <~ sub val/0 45 | pc <0? copy pc/break 46 | 47 | 48 | stack.parseBinarySpaceTree(stack.currentPos, val/128, val/66) -> number 49 | stack.currentPos <- add val/7 50 | 51 | stack.parseBinarySpaceTree(stack.currentPos, val/8, val/82) -> columnNumber 52 | stack.currentPos <- add val/3 53 | 54 | stack.number <- shl val/3 55 | stack.number <- add stack.columnNumber 56 | 57 | &seatMap <- copy val.seatMap 58 | &seatMap <- add stack.number 59 | seatMap <- copy val/1 60 | 61 | &r2 <- copy stack.number pop 62 | pc <- copy pc/loop 63 | } 64 | 65 | &seatMap <- copy val.seatMap 66 | { 67 | seatMap.occupied <~ or seatMap.occupied 68 | pc number { 93 | var stack.bitFlag/0 push <- copy stack.maxValue 94 | stack.bitFlag <- shr val/1 95 | stack.number <- copy val/0 96 | { 97 | stack.bitFlag <~ sub val/0 98 | pc <0? copy pc/break 99 | 100 | &str <- copy stack.str 101 | { 102 | str.char <~ sub stack.bChar 103 | pc -t= \ 11 | # examples/aoc/2020/day_5a.ucisc \ 12 | # app/lib/numbers.ucisc \ 13 | # app/lib/string_serial.ucisc \ 14 | # app/lib/strings.ucisc 15 | 16 | def stack/r1 <- copy val/0 17 | 18 | var val.bufferStart/1536 19 | var val.bufferLen/32768 20 | var val.echoOn/0 21 | var val.serialDevice/32 22 | 23 | def str/r2 24 | var str.char/0 25 | 26 | var stack.highest/0 push <- copy val/0 27 | 28 | &r2 <- copy val.bufferLen 29 | stack.readBuffer(val.bufferStart, &r2, val.echoOn, val.serialDevice) 30 | stack.printLine(pc/parsingData, val.serialDevice) 31 | 32 | var stack.currentPos/0 push <- copy val.bufferStart 33 | { 34 | 35 | stack.findEndOfWhitespace(stack.currentPos) -> nextStart 36 | stack.currentPos <- copy stack.nextStart 37 | &r2 <- copy stack.nextStart pop 38 | 39 | &str <- copy stack.currentPos 40 | str.char <~ sub val/0 41 | pc <0? copy pc/break 42 | 43 | 44 | stack.parseBinarySpaceTree(stack.currentPos, val/128, val/66) -> number 45 | stack.currentPos <- add val/7 46 | 47 | stack.parseBinarySpaceTree(stack.currentPos, val/8, val/82) -> columnNumber 48 | stack.currentPos <- add val/3 49 | 50 | stack.number <- shl val/3 51 | stack.number <- add stack.columnNumber 52 | 53 | stack.number <~ sub stack.highest 54 | { 55 | pc number { 74 | var stack.bitFlag/0 push <- copy stack.maxValue 75 | stack.bitFlag <- shr val/1 76 | stack.number <- copy val/0 77 | { 78 | stack.bitFlag <~ sub val/0 79 | pc <0? copy pc/break 80 | 81 | &str <- copy stack.str 82 | { 83 | str.char <~ sub stack.bChar 84 | pc -t= \ 11 | # examples/aoc/2020/day_4a.ucisc \ 12 | # app/lib/numbers.ucisc \ 13 | # app/lib/string_serial.ucisc \ 14 | # app/lib/strings.ucisc \ 15 | # app/lib/arrays.ucisc 16 | 17 | def stack/r1 <- copy val/0 18 | 19 | var val.listStart/1280 20 | var val.bufferStart/1536 21 | var val.bufferLen/32768 22 | var val.echoOn/0 23 | var val.serialDevice/32 24 | 25 | def buffer/r2 26 | var buffer.char/0 27 | 28 | &r2 <- copy val.bufferLen 29 | stack.readBuffer(val.bufferStart, &r2, val.echoOn, val.serialDevice) 30 | stack.printLine(pc/parsingData, val.serialDevice) 31 | 32 | var stack.totalSum/0 push <- copy val/0 33 | var stack.currentPos/0 push <- copy val.bufferStart 34 | { 35 | stack.detectNewline(stack.currentPos) -> charCount 36 | stack.currentPos <- add stack.charCount 37 | stack.detectNewline(stack.currentPos) -> charCount2 38 | { 39 | pc <0? copy pc/break 40 | 41 | # Add the group, reset the list 42 | stack.currentPos <- add stack.charCount2 43 | 44 | def array/r2 <- copy val.listStart 45 | var array.size/0 46 | stack.totalSum <- add array.size 47 | 48 | # Re-init array 49 | stack.createArray(val.listStart) 50 | } 51 | &r2 <- copy stack.charCount pop 52 | 53 | { 54 | stack.isLowercaseLetterChar(stack.currentPos) 55 | pc <0? copy pc/break 56 | 57 | &buffer <- copy stack.currentPos 58 | stack.arrayContains(val.listStart, buffer.char) 59 | pc answer 12 | 13 | &r1 <- copy stack.answer # Display on LEDs 14 | 15 | pc <- copy pc/0 # halt 16 | 17 | fun stack.factorial(n) -> result { 18 | stack.result <- copy stack.n 19 | 20 | stack.n push <- sub val/1 21 | var stack.n-1/0 22 | { 23 | pc <0? copy pc/break 24 | 25 | stack.factorial(stack.n-1) -> fact_n-1 26 | 27 | stack.result <- mult stack.fact_n-1 28 | 29 | &r3 <- copy stack.fact_n-1 pop 30 | } 31 | 32 | pc <- copy stack.return pop 33 | } 34 | -------------------------------------------------------------------------------- /examples/fib.ucisc: -------------------------------------------------------------------------------- 1 | # Compute Fibonacci numbers 2 | # 3 | # By default, computes fib(val/8) == val/21. fib(24) is the maximum 4 | # value that will compute correctly without overflow. 5 | # 6 | # To run: 7 | # $ ucisc examples/fib.ucisc 8 | 9 | def stack/r1 <- copy val/0 10 | 11 | stack.fib(val/24) -> result 12 | 13 | &r1 <- copy stack.result # Display on LEDs 14 | 15 | pc <- copy pc/0 # halt 16 | 17 | fun stack.fib(n) -> result { 18 | # fib(0) == 0 19 | # fib(1) == 1 20 | { 21 | stack.n <~ sub val/2 22 | pc <0? copy pc/break 23 | pc fib_n-1 32 | 33 | stack.n <- sub val/1 # replace n - 1 with n - 2 34 | stack.fib(stack.n) -> fib_n-2 35 | 36 | stack.fib_n-1 <- add stack.fib_n-2 37 | stack.result <- copy stack.fib_n-1 38 | 39 | pc <- copy stack.return pop 40 | } 41 | -------------------------------------------------------------------------------- /examples/knight.ucisc: -------------------------------------------------------------------------------- 1 | # Creates a knight rider effect in register 1 2 | 3 | # Init register 1 with value 1 4 | def knight/r1 <- copy val/1 5 | def counter/r2 <- copy val/0 6 | var val.reverse/256 7 | 8 | # Wait loop to eat up clock cycles 9 | # This should work for ~16 MHz processor 10 | wait: 11 | { 12 | &counter <- add val/1 13 | &counter <~ shl val/2 14 | pc result { 26 | def str/r2 <- copy stack.ptr pop 27 | var str.char/0 28 | 29 | { 30 | serial.flags <~ and val.writeReady 31 | pc <0? copy pc/loop # Not ready to write another byte yet 32 | 33 | str.char <~ or str.char 34 | pc <0? copy pc/break # end of string, null 35 | 36 | serial.tx <- copy str.char 37 | 38 | &str <- add val/1 39 | pc <- copy pc/loop 40 | } 41 | 42 | pc <- copy stack.return pop 43 | } 44 | -------------------------------------------------------------------------------- /examples/uart_screen_echo.ucisc: -------------------------------------------------------------------------------- 1 | # Writes test values over the serial interface 2 | 3 | def stack/r1 <- copy val/0 4 | 5 | # Lets define the serial device control space 6 | def serial/r4 <- copy val/32 7 | var serial.type/1 #LSB 8 | var serial.flags/1 #MSB 9 | var serial.tx/3 10 | var serial.rx/4 11 | var val.writeReady/256 12 | var val.readReady/512 13 | 14 | def screen/r5 <- copy val/4096 15 | var screen.char/0 16 | 17 | var stack.type/0 push <- lsb serial.type 18 | stack.type <~ sub val/4 19 | pc ,!,~ 18 | 19 | syntax keyword uciscOpcode <- <~ <0 <0? <1 34 | highlight link uciscArg Identifier 35 | 36 | syntax keyword uciscOption def var fun 37 | highlight link uciscOption Define 38 | 39 | syntax match uciscData /^[ ]*% *\([0-9a-fA-F][0-9a-fA-F][ ]*\)*/ 40 | highlight link uciscData Number 41 | 42 | set comments-=:# 43 | set comments+=n:# 44 | syntax match subxCommentedCode "#? .*" | highlight link subxCommentedCode CommentedCode 45 | let b:cmt_head = "#? " 46 | 47 | let &cpo = s:save_cpo 48 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokthis/ucisc/3c40a288d26409a64cf192b4cbad135579a4e0ac/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | distributionBase=GRADLE_USER_HOME 2 | distributionPath=wrapper/dists 3 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.0-bin.zip 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @rem 2 | @rem Copyright 2015 the original author or authors. 3 | @rem 4 | @rem Licensed under the Apache License, Version 2.0 (the "License"); 5 | @rem you may not use this file except in compliance with the License. 6 | @rem You may obtain a copy of the License at 7 | @rem 8 | @rem https://www.apache.org/licenses/LICENSE-2.0 9 | @rem 10 | @rem Unless required by applicable law or agreed to in writing, software 11 | @rem distributed under the License is distributed on an "AS IS" BASIS, 12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | @rem See the License for the specific language governing permissions and 14 | @rem limitations under the License. 15 | @rem 16 | 17 | @if "%DEBUG%" == "" @echo off 18 | @rem ########################################################################## 19 | @rem 20 | @rem Gradle startup script for Windows 21 | @rem 22 | @rem ########################################################################## 23 | 24 | @rem Set local scope for the variables with windows NT shell 25 | if "%OS%"=="Windows_NT" setlocal 26 | 27 | set DIRNAME=%~dp0 28 | if "%DIRNAME%" == "" set DIRNAME=. 29 | set APP_BASE_NAME=%~n0 30 | set APP_HOME=%DIRNAME% 31 | 32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter. 33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi 34 | 35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" 37 | 38 | @rem Find java.exe 39 | if defined JAVA_HOME goto findJavaFromJavaHome 40 | 41 | set JAVA_EXE=java.exe 42 | %JAVA_EXE% -version >NUL 2>&1 43 | if "%ERRORLEVEL%" == "0" goto execute 44 | 45 | echo. 46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 47 | echo. 48 | echo Please set the JAVA_HOME variable in your environment to match the 49 | echo location of your Java installation. 50 | 51 | goto fail 52 | 53 | :findJavaFromJavaHome 54 | set JAVA_HOME=%JAVA_HOME:"=% 55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 56 | 57 | if exist "%JAVA_EXE%" goto execute 58 | 59 | echo. 60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 61 | echo. 62 | echo Please set the JAVA_HOME variable in your environment to match the 63 | echo location of your Java installation. 64 | 65 | goto fail 66 | 67 | :execute 68 | @rem Setup the command line 69 | 70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 71 | 72 | 73 | @rem Execute Gradle 74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* 75 | 76 | :end 77 | @rem End local scope for the variables with windows NT shell 78 | if "%ERRORLEVEL%"=="0" goto mainEnd 79 | 80 | :fail 81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 82 | rem the _cmd.exe /c_ return code! 83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 84 | exit /b 1 85 | 86 | :mainEnd 87 | if "%OS%"=="Windows_NT" endlocal 88 | 89 | :omega 90 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/ecp5/pll.v: -------------------------------------------------------------------------------- 1 | module pll(input clki, output clko); 2 | (* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) 3 | 4 | parameter CLKI_DIV = 1; 5 | parameter CLKFB_DIV = 1; 6 | parameter CLKOP_DIV = 1; 7 | 8 | EHXPLLL #( 9 | .PLLRST_ENA("DISABLED"), 10 | .INTFB_WAKE("DISABLED"), 11 | .STDBY_ENABLE("DISABLED"), 12 | .DPHASE_SOURCE("DISABLED"), 13 | .CLKOP_FPHASE(0), 14 | .CLKOP_CPHASE(11), 15 | .OUTDIVIDER_MUXA("DIVA"), 16 | .CLKOP_ENABLE("ENABLED"), 17 | .CLKOP_DIV(CLKOP_DIV), 18 | .CLKFB_DIV(CLKFB_DIV), 19 | .CLKI_DIV(CLKI_DIV), 20 | .FEEDBK_PATH("CLKOP") 21 | ) pll_i ( 22 | .CLKI(clki), 23 | .CLKFB(clko), 24 | .CLKOP(clko), 25 | .RST(1'b0), 26 | .STDBY(1'b0), 27 | .PHASESEL0(1'b0), 28 | .PHASESEL1(1'b0), 29 | .PHASEDIR(1'b0), 30 | .PHASESTEP(1'b0), 31 | .PLLWAKESYNC(1'b0), 32 | .ENCLKOP(1'b0) 33 | ); 34 | endmodule 35 | 36 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/ice40/pll.v: -------------------------------------------------------------------------------- 1 | module pll(input clki, output clko); 2 | parameter CLK_DIVR = 0; 3 | parameter CLK_DIVF = 0; 4 | 5 | SB_PLL40_CORE #( 6 | .FEEDBACK_PATH("PHASE_AND_DELAY"), 7 | .DELAY_ADJUSTMENT_MODE_FEEDBACK("FIXED"), 8 | .DELAY_ADJUSTMENT_MODE_RELATIVE("FIXED"), 9 | .PLLOUT_SELECT("SHIFTREG_0deg"), 10 | .SHIFTREG_DIV_MODE(1'b0), 11 | .FDA_FEEDBACK(4'h0), 12 | .FDA_RELATIVE(4'h0), 13 | .DIVR(CLK_DIVR), 14 | .DIVF(CLK_DIVF), 15 | .DIVQ(3'h0), 16 | .FILTER_RANGE(3'b001), 17 | ) uut ( 18 | .REFERENCECLK (clki), 19 | .PLLOUTGLOBAL (clko), 20 | .BYPASS (1'b0), 21 | .RESETB (1'b1) 22 | ); 23 | 24 | endmodule 25 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input [15:0] source, 3 | input [15:0] destination, 4 | input [3:0] op_code, 5 | input [15:0] flags, 6 | output [15:0] result_out, 7 | output overflow, 8 | output carry 9 | ); 10 | 11 | wire [31:0] mult_result = source * destination; 12 | 13 | wire [31:0] signed_shift_destination = { {16{flags[8] & destination[15]}}, destination }; 14 | assign result_out = result[15:0]; 15 | assign carry = result[16]; 16 | assign overflow = carry; 17 | wire [16:0] result = 18 | //Bit operations 19 | op_code == 4'h0 ? source : // Copy 20 | op_code == 4'h1 ? source & destination : // AND 21 | op_code == 4'h2 ? source | destination : // OR 22 | op_code == 4'h3 ? source ^ destination : // XOR 23 | op_code == 4'h4 ? ~source + 1 : // 2's compliment 24 | 25 | //Shift operations 26 | op_code == 4'h5 ? { 1'h0, (source[15:4] == 12'h0 ? destination << source[3:0] : 16'h0) } : // Shift left 27 | // shift signed/unsigned by sign flag 28 | op_code == 4'h6 ? source > 16'hF ? {16{flags[8] & destination[15]}} : signed_shift_destination >> source[3:0] : 29 | op_code == 4'h7 ? { source[7:0], source[15:8] } : // Swap 30 | op_code == 4'h8 ? { source[15:8], 8'h00 } : // High byte 31 | op_code == 4'h9 ? { 8'h00, source[7:0] } : // Low byte 32 | 33 | op_code == 4'hA ? destination + source : // Add 34 | op_code == 4'hB ? destination + ~source + 1 : // Subtract 35 | op_code == 4'hC ? mult_result[15:0] : // Multiply 36 | op_code == 4'hD ? mult_result[31:16] : // Multiply upper word 37 | op_code == 4'hE ? destination + source + flags[2] : // Add with carry 38 | 0; // TBD 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/basic_memory_block.v: -------------------------------------------------------------------------------- 1 | module basic_memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [WIDTH-1:0] read_address, 5 | input [WIDTH-1:0] write_address, 6 | input [15:0] data_in, 7 | output reg [15:0] data_out, 8 | ); 9 | parameter WIDTH = 8; 10 | parameter mem_depth = 1 << WIDTH; 11 | 12 | reg [15:0] mem[mem_depth-1:0]; 13 | 14 | always @(posedge clock) begin 15 | data_out <= mem[read_address]; 16 | 17 | if(write_enable) 18 | mem[write_address[WIDTH-1:0]] <= data_in; 19 | end 20 | endmodule 21 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/devices.v: -------------------------------------------------------------------------------- 1 | module devices ( 2 | input ref_clock, 3 | input cpu_clock, 4 | input write_enable, 5 | input [15:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output reg [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | wire control = address[15:12] == 4'h0; 14 | wire [7:0] target_device = control ? address[11:4] : address[15:8]; 15 | 16 | always @(posedge cpu_clock) begin 17 | data_out <= 18 | target_device == 8'h02 ? uart_data_out : 19 | target_device == 8'h10 ? 16'h0 : //graphics_data_out : 20 | 16'h0; 21 | end 22 | 23 | wire [15:0] uart_data_out; 24 | uart_device #(.DEVICE_ID(16'h100)) uart_device( 25 | .clock(cpu_clock), 26 | .write_enable(write_enable & target_device == 8'h2), 27 | .control(control), 28 | .address(address[7:0]), 29 | .data_in(data_in), 30 | .rx(rx), 31 | .data_out(uart_data_out), 32 | .tx(tx), 33 | .peek(peek) 34 | ); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/dff.v: -------------------------------------------------------------------------------- 1 | module dff( 2 | input clock, 3 | input [WIDTH-1:0] d, 4 | input async_reset, 5 | input enable, 6 | output reg [WIDTH-1:0] q 7 | ); 8 | parameter WIDTH = 1; 9 | parameter INIT = {WIDTH{1'b0}}; 10 | 11 | initial q = INIT; 12 | 13 | always @ (posedge clock or posedge async_reset) 14 | if (async_reset) begin 15 | q <= INIT; 16 | end else if (enable == 1) begin 17 | q <= d; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder ( 2 | input [15:0] flags, 3 | input [2:0] effect, 4 | output store 5 | ); 6 | assign store = 7 | effect == 3'h0 ? flags[0] : 8 | effect == 3'h1 ? ~flags[0] : 9 | effect == 3'h2 ? flags[1] : 10 | effect == 3'h3 ? ~flags[1] & ~flags[0] : 11 | effect == 3'h4 ? 1 : 12 | effect == 3'h5 ? flags[3] : 13 | effect == 3'h6 ? flags[4] : 14 | 0; 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/gpio_device.v: -------------------------------------------------------------------------------- 1 | module gpio_device( 2 | input cpu_clock, 3 | input write_enable, 4 | input is_control, 5 | input [7:0] short_address, 6 | input [15:0] cpu_data_in, 7 | output reg [15:0] cpu_data_out, 8 | input [PINS-1:0] gpio_in, 9 | output reg [PINS-1:0] gpio_out, 10 | output reg [PINS-1:0] gpio_config, 11 | ); 12 | parameter PINS = 16; 13 | parameter DEVICE_ID = 16'h0; 14 | parameter DEVICE_TYPE = 8'h8; 15 | 16 | wire [5:0] pin_count = PINS - 1; 17 | 18 | wire control_write = is_control & write_enable; 19 | wire [3:0] control_address = short_address[3:0]; 20 | 21 | wire [7:0] flags = { pin_count, 2'h0 }; 22 | wire [15:0] control_read = 23 | control_address == 4'h0 ? DEVICE_ID : 24 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 25 | control_address == 4'h2 ? 16'h0 : 26 | control_address == 4'h3 ? 16'h0 : 27 | control_address == 4'h4 ? gpio_config[15:0] : 28 | control_address == 4'h5 ? (PINS > 16 ? gpio_config[31:16] : 16'h0) : 29 | control_address == 4'h6 ? (PINS > 32 ? gpio_config[47:32] : 16'h0) : 30 | control_address == 4'h7 ? (PINS > 48 ? gpio_config[63:48] : 16'h0) : 31 | control_address == 4'h8 ? gpio_out[15:0] : 32 | control_address == 4'h9 ? (PINS > 16 ? gpio_out[31:0] : 16'h0) : 33 | control_address == 4'hA ? (PINS > 16 ? gpio_out[47:32] : 16'h0) : 34 | control_address == 4'hB ? (PINS > 16 ? gpio_out[63:48] : 16'h0) : 35 | control_address == 4'hC ? gpio_in[15:0] : 36 | control_address == 4'hD ? (PINS > 16 ? gpio_in[31:16] : 16'h0) : 37 | control_address == 4'hE ? (PINS > 16 ? gpio_in[47:32] : 16'h0) : 38 | (PINS > 16 ? gpio_in[63:48] : 16'h0); 39 | 40 | always @(posedge cpu_clock) begin 41 | cpu_data_out <= is_control ? control_read : 16'h0; 42 | end 43 | 44 | always @(posedge cpu_clock) begin 45 | if(control_write) begin 46 | if(control_address == 4'h4) 47 | gpio_config[15:0] <= cpu_data_in; 48 | else if(PINS > 16 && control_address == 4'h5) 49 | gpio_config[31:16] <= cpu_data_in; 50 | else if(PINS > 32 && control_address == 4'h6) 51 | gpio_config[47:32] <= cpu_data_in; 52 | else if(PINS > 48 && control_address == 4'h7) 53 | gpio_config[63:48] <= cpu_data_in; 54 | else if(control_address == 4'h8) 55 | gpio_out[15:0] <= cpu_data_in; 56 | else if(PINS > 16 && control_address == 4'h9) 57 | gpio_out[31:16] <= cpu_data_in; 58 | else if(PINS > 32 && control_address == 4'hA) 59 | gpio_out[47:32] <= cpu_data_in; 60 | else if(PINS > 48 && control_address == 4'hB) 61 | gpio_out[63:48] <= cpu_data_in; 62 | end 63 | end 64 | endmodule 65 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/memory_block.v: -------------------------------------------------------------------------------- 1 | module memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [WIDTH-1:0] read_address, 5 | input [WIDTH-1:0] write_address, 6 | input [15:0] data_in, 7 | output [15:0] data_out, 8 | output reg [15:0] data_out_a, 9 | output reg [15:0] data_out_b, 10 | output reg primary_out_select 11 | ); 12 | 13 | parameter WIDTH = 15; 14 | parameter mem_depth = 1 << (WIDTH - 1); 15 | parameter MEM_INIT_FILEA = "prog.hex.a.hex"; 16 | parameter MEM_INIT_FILEB = "prog.hex.b.hex"; 17 | 18 | reg [15:0] memA[mem_depth-1:0]; 19 | reg [15:0] memB[mem_depth-1:0]; 20 | 21 | initial begin 22 | $readmemh(MEM_INIT_FILEA, memA); 23 | $readmemh(MEM_INIT_FILEB, memB); 24 | end 25 | 26 | always@(posedge clock) begin 27 | primary_out_select <= read_address[0]; 28 | end 29 | assign data_out = primary_out_select ? data_out_b : data_out_a; 30 | 31 | wire [WIDTH-2:0] readA = read_address[0] ? read_address[WIDTH-1:1] + 1 : read_address[WIDTH-1:1]; 32 | always @(posedge clock) begin 33 | data_out_a <= memA[readA]; 34 | 35 | if(write_enable & ~write_address[0]) 36 | memA[write_address[WIDTH-1:1]] <= data_in; 37 | end 38 | 39 | wire [WIDTH-2:0] readB = read_address[WIDTH-1:1]; 40 | always @(posedge clock) begin 41 | data_out_b <= memB[readB]; 42 | 43 | if(write_enable & write_address[0]) 44 | memB[write_address[WIDTH-1:1]] <= data_in; 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/parallel_buffer.v: -------------------------------------------------------------------------------- 1 | module parallel_buffer( 2 | input clock, 3 | input [WIDTH-1:0] data_in, 4 | input write_in, 5 | input next_ready, 6 | output write_ready, 7 | output reg [WIDTH-1:0] data_out, 8 | output reg write_out 9 | ); 10 | parameter WIDTH = 8; 11 | initial write_out = 0; 12 | 13 | assign write_ready = ~write_out | next_ready; 14 | 15 | always @(posedge clock) begin 16 | if (write_ready & write_in) begin 17 | data_out <= data_in; 18 | write_out <= 1'b1; 19 | end else if (write_out & next_ready) begin 20 | data_out <= 0; 21 | write_out <= 1'b0; 22 | end 23 | end 24 | endmodule -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/uart_device.v: -------------------------------------------------------------------------------- 1 | module uart_device( 2 | input clock, 3 | input write_enable, 4 | input control, 5 | input [7:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | assign peek = control_read; 14 | 15 | parameter DEVICE_ID = 16'h0; 16 | parameter DEVICE_TYPE = 8'h4; 17 | 18 | wire control_write = control & write_enable; 19 | wire [3:0] control_address = address[3:0]; 20 | wire [7:0] rx_data_out; 21 | wire rx_data_ready; 22 | 23 | wire [15:0] control_read = 24 | control_address == 4'h0 ? DEVICE_ID : 25 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 26 | control_address == 4'h2 ? baud_clock_divider : 27 | control_address == 4'h4 ? { 8'h0, rx_data_out } : 28 | 16'h0; 29 | 30 | assign data_out = control ? control_read : 16'h0; 31 | 32 | wire in_progress = ~write_ready | ~ready_p1p2 | ~tx_ready; 33 | wire [7:0] flags = { 4'h1, 1'b0, in_progress, rx_data_ready, write_ready }; 34 | 35 | reg [15:0] baud_clock_divider; 36 | initial baud_clock_divider = 16'h446; // 115200 baud 37 | 38 | wire buffer_write_en = control_write & control_address == 4'h3; 39 | 40 | always @(posedge clock) begin 41 | if (control_write & control_address == 4'h2) 42 | baud_clock_divider <= data_in; 43 | end 44 | 45 | wire write_p1p2; 46 | wire ready_p1p2; 47 | wire [7:0] data_p1p2; 48 | wire tx_ready; 49 | wire [7:0] tx_data; 50 | wire tx_write; 51 | 52 | wire write_ready; 53 | parallel_buffer #(.WIDTH(8)) pb1( 54 | .clock(clock), 55 | .data_in(data_in[7:0]), 56 | .write_in(buffer_write_en), 57 | .next_ready(ready_p1p2), 58 | .write_ready(write_ready), 59 | .data_out(data_p1p2), 60 | .write_out(write_p1p2) 61 | ); 62 | 63 | parallel_buffer #(.WIDTH(8)) pb2( 64 | .clock(clock), 65 | .data_in(data_p1p2), 66 | .write_in(write_p1p2), 67 | .next_ready(tx_ready), 68 | .write_ready(ready_p1p2), 69 | .data_out(tx_data), 70 | .write_out(tx_write) 71 | ); 72 | 73 | uart_tx uart_tx( 74 | .clock(clock), 75 | .clock_divider(baud_clock_divider), 76 | .data_in(tx_data), 77 | .write_en(tx_write), 78 | .data_ready(tx_ready), 79 | .tx(tx) 80 | ); 81 | 82 | wire [15:0] rx_buffer_out; 83 | 84 | uart_rx uart_rx( 85 | .clock(clock), 86 | .clock_divider(baud_clock_divider), 87 | .read_en(control_address == 4'h4 & control_write), 88 | .rx(rx), 89 | .data_ready(rx_data_ready), 90 | .data_out(rx_data_out) 91 | ); 92 | endmodule 93 | -------------------------------------------------------------------------------- /hardware/00_uCISC/src/processor/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input [WIDTH-1:0] data_in, 5 | input write_en, 6 | output data_ready, 7 | output tx 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | reg [15:0] clock_count = 16'h0; 12 | reg [WIDTH+1:0] data = 10'h0; 13 | reg [3:0] shift_remaining = 4'h0; 14 | assign tx = data_ready | data[0]; 15 | assign data_ready = shift_remaining == 0; 16 | 17 | always @(posedge clock) begin 18 | if (data_ready & write_en) begin 19 | data <= { 1'b1, data_in, 1'b0 }; 20 | shift_remaining <= WIDTH + 2; 21 | clock_count <= 0; 22 | end else if (~data_ready) begin 23 | if (clock_count == clock_divider) begin 24 | shift_remaining <= shift_remaining - 1'b1; 25 | data <= { 2'b1, data[WIDTH:1] }; 26 | clock_count <= 16'h0; 27 | end else begin 28 | clock_count <= clock_count + 1'b1; 29 | end 30 | end 31 | end 32 | endmodule -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/Makefile: -------------------------------------------------------------------------------- 1 | TRELLIS?=/usr/share/trellis 2 | PROJ = ecp5_reference 3 | VERILOG := top.v $(wildcard src/*.v) 4 | TESTS := $(basename $(wildcard **/*_tb.v)) 5 | 6 | PIN_DEF = ecp5_5g_eval.lpf 7 | DEVICE = um5g-85k 8 | FREQ_TARGET = 50 9 | 10 | all: prog 11 | 12 | $(PROJ).json: $(VERILOG) #firmware.hex 13 | yosys -p "synth_ecp5 -json $@ -top top" $(VERILOG) 14 | 15 | $(PROJ)_out.config: $(PROJ).json $(PIN_DEF) 16 | nextpnr-ecp5 --json $(PROJ).json --lpf $(PIN_DEF) --textcfg $@ --$(DEVICE) --freq $(FREQ_TARGET) --package CABGA381 17 | 18 | $(PROJ).svf: $(PROJ)_out.config 19 | ecppack --svf-rowsize 100000 --svf $(PROJ).svf $< $@ 20 | 21 | prog: $(PROJ).svf 22 | openocd -f ${TRELLIS}/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf $<; exit" 23 | 24 | clean: 25 | rm -f $(PROJ).json $(PROJ)_out.config $(PROJ).svf **/*.v.iverilog* 26 | 27 | verify: $(TESTS) 28 | @echo "Tests complete." 29 | 30 | $(TESTS): %: %.v.iverilog 31 | 32 | ./test/%.v.iverilog: test/%.v 33 | @iverilog -o $@.out test/defines.v $(VERILOG) $^ 34 | @vvp $@.out > $@.results 35 | @if grep "ASSERTION FAILED" $@.results; \ 36 | then echo "Tests failed - $^"; echo "Run 'vvp $@.out' for results"; exit 1; \ 37 | else echo "Tests passed - $^"; \ 38 | fi 39 | 40 | .SECONDARY: 41 | .PHONY: all prog clean 42 | -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/README.md: -------------------------------------------------------------------------------- 1 | # uCISC Hardware Implementation 2 | 3 | The reference hardware implementation uses [project icestorm](http://www.clifford.at/icestorm/) 4 | to target the [TinyFPGA Bx board](https://tinyfpga.com/). As of this writing, 5 | the CPU has most of the functionality in the specs. It is able to do basic 6 | animations with LEDs (See [knight.ucisc](../examples/knight.ucisc)) and compute 7 | [fibonacci numbers](../examples/fib.ucisc). The contents of pc and r1 are sent 8 | to output pins you can hook up to LEDs to see the results (See 9 | [reference/top.v](reference/top.v) for the pinout - don't forget current 10 | limiting resistors on your LEDs). 11 | 12 | #### Basic Architecture 13 | 14 | The CPU is a 4 stage reference implementation broken up into the following 15 | stages: 16 | 17 | * Stage 0: Store result, load next instruction from memory 18 | * Stage 1: Load immediate from memory 19 | * Stage 2: Load source value from memory, or compute source from registers 20 | * Stage 3: Load dest value from memory, or compute dest from registers 21 | 22 | It has all 6 general purpose registers. 23 | 24 | Not implemented: 25 | * Manipulating the flags register other than as a result of the ALU calculation. 26 | * Manipulating the interrupt register 27 | * Memory banking for devices 28 | 29 | #### Usage 30 | 31 | 1. Follow the [project icestorm](http://www.clifford.at/icestorm/) install 32 | instructions for the yosys toolchain. 33 | 34 | 2. Compile your uCISC code to reference/prog.hex. You can use the 35 | [uCISC kotlin emulator](https://github.com/grokthis/ucisc-kotlin) for this. If 36 | you follow the install instructions there, you can run something like 37 | `ucisc -c > reference/prog.hex` to compile your code. 38 | 39 | 3. From the reference directory, do `make clean` and `make prog` with the 40 | TinyFPGA Bx board plugged into your computer. Make sure the bootloader on the 41 | FPGA is running. You may need `make sudo-prog` if your user doesn't have 42 | permissions to connect to the board. 43 | 44 | Note: You will want to hook a reset button to pin 2 with a pull down resistor. 45 | Setting reset to 3.3v will start the program over. The bootstrap process isn't 46 | as clean as I would like and sometimes program start doesn't work immediately 47 | after bootstrap and you need to reset it once. I should be able to work this 48 | out in a future release. 49 | 50 | #### Tests 51 | 52 | Install [Icarus Verilog](http://iverilog.icarus.com/) to run the tests. Then, from 53 | the reference directory, run `./run_tests` to run all tests. Note any warnings, 54 | compile errors or test failures in the output. 55 | 56 | #### Status 57 | 58 | Currently, the implementation takes about 25-35% of the resources on the 59 | Bx board, not including BRAMs of which I use all 32. I have not included 60 | devices or division in the ALU yet. In theory there is room for 2 CPUs with 61 | 4k x 16 block memory each and a couple of simple devices if you leave out 62 | the division opcode. 63 | 64 | I have successfully run at a full 16MHz without division and 8MHz with, but 65 | I may not have hit the critical long path yet with my limited testing. Time 66 | will tell, though fib(24) does push a lot of additions and memory operations 67 | through the processor. -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/ecp5_5g_eval.lpf: -------------------------------------------------------------------------------- 1 | LOCATE COMP "CLK12" SITE "A10"; 2 | IOBUF PORT "CLK12" IO_TYPE=LVCMOS33; 3 | 4 | LOCATE COMP "UART_TX" SITE "A14"; 5 | LOCATE COMP "UART_RX" SITE "B10"; 6 | IOBUF PORT "UART_TX" IO_TYPE=LVCMOS33; 7 | IOBUF PORT "UART_RX" IO_TYPE=LVCMOS33; 8 | 9 | LOCATE COMP "DIP1" SITE "J1"; 10 | LOCATE COMP "DIP2" SITE "H1"; 11 | LOCATE COMP "DIP3" SITE "K1"; 12 | LOCATE COMP "DIP4" SITE "E15"; 13 | LOCATE COMP "DIP5" SITE "D16"; 14 | LOCATE COMP "DIP6" SITE "B16"; 15 | LOCATE COMP "DIP7" SITE "C16"; 16 | LOCATE COMP "DIP8" SITE "A16"; 17 | IOBUF PORT "DIP1" IO_TYPE=LVCMOS33; 18 | IOBUF PORT "DIP2" IO_TYPE=LVCMOS33; 19 | IOBUF PORT "DIP3" IO_TYPE=LVCMOS33; 20 | IOBUF PORT "DIP4" IO_TYPE=LVCMOS33; 21 | IOBUF PORT "DIP5" IO_TYPE=LVCMOS33; 22 | IOBUF PORT "DIP6" IO_TYPE=LVCMOS33; 23 | IOBUF PORT "DIP7" IO_TYPE=LVCMOS33; 24 | IOBUF PORT "DIP8" IO_TYPE=LVCMOS33; 25 | 26 | LOCATE COMP "SW2" SITE "G2"; 27 | IOBUF PORT "SW2" IO_TYPE=LVCMOS33; 28 | 29 | LOCATE COMP "LED[0]" SITE "A13"; 30 | LOCATE COMP "LED[1]" SITE "A12"; 31 | LOCATE COMP "LED[2]" SITE "B19"; 32 | LOCATE COMP "LED[3]" SITE "A18"; 33 | LOCATE COMP "LED[4]" SITE "B18"; 34 | LOCATE COMP "LED[5]" SITE "C17"; 35 | LOCATE COMP "LED[6]" SITE "A17"; 36 | LOCATE COMP "LED[7]" SITE "B17"; 37 | IOBUF PORT "LED[0]" IO_TYPE=LVCMOS25; 38 | IOBUF PORT "LED[1]" IO_TYPE=LVCMOS25; 39 | IOBUF PORT "LED[2]" IO_TYPE=LVCMOS25; 40 | IOBUF PORT "LED[3]" IO_TYPE=LVCMOS25; 41 | IOBUF PORT "LED[4]" IO_TYPE=LVCMOS25; 42 | IOBUF PORT "LED[5]" IO_TYPE=LVCMOS25; 43 | IOBUF PORT "LED[6]" IO_TYPE=LVCMOS25; 44 | IOBUF PORT "LED[7]" IO_TYPE=LVCMOS25; 45 | 46 | LOCATE COMP "PIXEL[0]" SITE "K4"; 47 | LOCATE COMP "PIXEL[1]" SITE "D14"; 48 | LOCATE COMP "PIXEL[2]" SITE "P1"; 49 | LOCATE COMP "PIXEL[3]" SITE "C14"; 50 | LOCATE COMP "PIXEL[4]" SITE "L1"; 51 | LOCATE COMP "PIXEL[5]" SITE "E12"; 52 | LOCATE COMP "PIXEL[6]" SITE "C12"; 53 | LOCATE COMP "PIXEL[7]" SITE "E11"; 54 | LOCATE COMP "PIXEL[8]" SITE "B20"; 55 | LOCATE COMP "PIXEL[9]" SITE "C15"; 56 | LOCATE COMP "PIXEL[10]" SITE "D15"; 57 | LOCATE COMP "PIXEL[11]" SITE "L5"; 58 | LOCATE COMP "PIXEL[12]" SITE "K3"; 59 | LOCATE COMP "PIXEL[13]" SITE "J5"; 60 | LOCATE COMP "PIXEL[14]" SITE "G1"; 61 | LOCATE COMP "PIXEL[15]" SITE "F1"; 62 | LOCATE COMP "PIXEL_CLK" SITE "B10"; 63 | LOCATE COMP "H_SYNC" SITE "E7"; 64 | LOCATE COMP "V_SYNC" SITE "A11"; 65 | 66 | IOBUF PORT "PIXEL[0]" IO_TYPE=LVCMOS33; 67 | IOBUF PORT "PIXEL[1]" IO_TYPE=LVCMOS33; 68 | IOBUF PORT "PIXEL[2]" IO_TYPE=LVCMOS33; 69 | IOBUF PORT "PIXEL[3]" IO_TYPE=LVCMOS33; 70 | IOBUF PORT "PIXEL[4]" IO_TYPE=LVCMOS33; 71 | IOBUF PORT "PIXEL[5]" IO_TYPE=LVCMOS33; 72 | IOBUF PORT "PIXEL[6]" IO_TYPE=LVCMOS33; 73 | IOBUF PORT "PIXEL[7]" IO_TYPE=LVCMOS33; 74 | IOBUF PORT "PIXEL[8]" IO_TYPE=LVCMOS33; 75 | IOBUF PORT "PIXEL[9]" IO_TYPE=LVCMOS33; 76 | IOBUF PORT "PIXEL[10]" IO_TYPE=LVCMOS33; 77 | IOBUF PORT "PIXEL[11]" IO_TYPE=LVCMOS33; 78 | IOBUF PORT "PIXEL[12]" IO_TYPE=LVCMOS33; 79 | IOBUF PORT "PIXEL[13]" IO_TYPE=LVCMOS33; 80 | IOBUF PORT "PIXEL[14]" IO_TYPE=LVCMOS33; 81 | IOBUF PORT "PIXEL[15]" IO_TYPE=LVCMOS33; 82 | IOBUF PORT "PIXEL_CLK" IO_TYPE=LVCMOS33; 83 | IOBUF PORT "H_SYNC" IO_TYPE=LVCMOS33; 84 | IOBUF PORT "V_SYNC" IO_TYPE=LVCMOS33; 85 | 86 | -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 4d40 0020 4e40 1000 91c9 0001 417b 0004 0010 0000 4640 1000 4740 1000 2 | 767b 0000 0000 0018 7740 ffff 3a40 0000 ee40 0001 4e7b 1100 0020 0004 4e40 1000 3 | 4971 1100 0000 0008 3940 3000 477b 0800 4700 1000 4971 1200 0000 000a 92c0 0004 4 | 4940 4000 467b 0800 4600 1000 0040 ffda -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/prog.hex.a.hex: -------------------------------------------------------------------------------- 1 | 4540 4d40 4e40 91c9 417b 0010 4640 4740 767b 2 | 0000 7740 3a40 ee40 4e7b 0020 4e40 4971 3 | 0000 3940 477b 4700 4971 0000 92c0 4940 4 | 467b 4600 0040 -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/prog.hex.b.hex: -------------------------------------------------------------------------------- 1 | 0000 0020 1000 0001 0004 0000 1000 1000 2 | 0000 0018 ffff 0000 0001 1100 0004 1000 3 | 1100 0008 3000 0800 1000 1200 000a 0004 4 | 4000 0800 1000 ffda -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | iverilog -o test_bench \ 5 | test/defines.v \ 6 | src/dff.v test/dff_tb.v 7 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 8 | echo "Found $FAILURES failures in dff_tb.v." 9 | 10 | iverilog -o test_bench \ 11 | test/defines.v \ 12 | src/memory_block.v test/memory_block_tb.v 13 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 14 | echo "Found $FAILURES failures in memory_block_tb.v." 15 | 16 | iverilog -o test_bench \ 17 | test/defines.v \ 18 | src/alu.v test/alu_tb.v 19 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 20 | echo "Found $FAILURES failures in alu_tb.v." 21 | 22 | iverilog -o test_bench \ 23 | test/defines.v \ 24 | src/effect_decoder.v test/effect_decoder_tb.v 25 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 26 | echo "Found $FAILURES failures in effect_decoder_tb.v." 27 | 28 | iverilog -o test_bench \ 29 | test/defines.v \ 30 | src/uart_tx.v test/uart_tx_tb.v 31 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 32 | echo "Found $FAILURES failures in uart_tx_tb.v." 33 | 34 | iverilog -o test_bench \ 35 | test/defines.v \ 36 | src/alu.v \ 37 | src/dff.v \ 38 | src/effect_decoder.v \ 39 | src/memory_block.v \ 40 | src/parallel_buffer.v \ 41 | src/uart_tx.v \ 42 | src/uart_rx.v \ 43 | src/uart_device.v \ 44 | src/devices.v \ 45 | src/cpu.v test/cpu_tb.v 46 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 47 | echo "Found $FAILURES failures in cpu_tb.v." 48 | 49 | #iverilog -o test_bench \ 50 | # test/defines.v \ 51 | # src/parallel_buffer.v \ 52 | # src/uart_tx.v \ 53 | # src/uart_device.v test/uart_device_tb.v 54 | #FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 55 | #echo "Found $FAILURES failures in uart_device_tb.v." 56 | 57 | iverilog -o test_bench \ 58 | test/defines.v \ 59 | src/uart_rx.v test/uart_rx_tb.v 60 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 61 | echo "Found $FAILURES failures in uart_rx_tb.v." 62 | -------------------------------------------------------------------------------- /hardware/01_GK110/ECP5/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input CLK12, 3 | input DIP1, 4 | input DIP2, 5 | input DIP3, 6 | input DIP4, 7 | input DIP5, 8 | input DIP6, 9 | input DIP7, 10 | input DIP8, 11 | input SW2, 12 | output UART_TX, 13 | input UART_RX, 14 | // output [7:0] LED, 15 | output [15:0] PIXEL, 16 | output H_SYNC, 17 | output V_SYNC 18 | ); 19 | 20 | parameter CLOCK_DIV = 10; 21 | parameter CLOCK_MULT = 85; 22 | 23 | //assign LED[7] = ~r1[7]; 24 | //assign LED[6] = ~r1[6]; 25 | //assign LED[5] = ~r1[5]; 26 | //assign LED[4] = ~r1[4]; 27 | //assign LED[3] = ~r1[3]; 28 | //assign LED[2] = ~r1[2]; 29 | //assign LED[1] = ~r1[1]; 30 | //assign LED[0] = ~r1[0]; 31 | 32 | assign UART_TX = tx; 33 | wire rx = UART_RX; 34 | 35 | //wire [15:0] r1; 36 | wire tx; 37 | //assign LED = tx; 38 | 39 | wire ref_clock = CLK12; 40 | wire cpu_clock; 41 | pll #( 42 | .CLKI_DIV(CLOCK_DIV), 43 | .CLKFB_DIV(CLOCK_MULT), 44 | .CLKOP_DIV(1), 45 | ) 46 | pll_cpu ( 47 | .clki(CLK12), 48 | .clko(cpu_clock) 49 | ); 50 | 51 | cpu #( 52 | .CLOCK_DIV(10), 53 | .CLOCK_MULT(105) 54 | ) cpu( 55 | .clk(CLK12), 56 | .reset(0), 57 | // .r1_peek(r1), 58 | .tx(tx), 59 | .rx(rx)//, 60 | //.pixel_out(PIXEL), 61 | //.h_sync_signal(H_SYNC), 62 | //.v_sync_signal(V_SYNC) 63 | ); 64 | 65 | wire control = 1'b1; 66 | wire vga_control_we = ~SW2; 67 | wire [15:0] data_input = { 8'h0, DIP8, DIP7, DIP6, DIP5, DIP4, DIP3, DIP2, DIP1 }; 68 | 69 | wire [15:0] graphics_data_out; 70 | vga_device vga_device( 71 | .ref_clock(ref_clock), 72 | .cpu_clock(cpu_clock), 73 | .control(control), //control), 74 | // .write_enable(write_enable & target_device == 8'h10), 75 | .write_enable(vga_control_we), 76 | // .write_address(address[7:0]), 77 | .write_address(16'h0002), 78 | // .data_in(data_in), 79 | .data_in(data_input), 80 | .read_enable(1'h0), 81 | .read_address(8'h0), //address[7:0]), 82 | //.data_out(graphics_data_out), 83 | .pixel_out(PIXEL), //pixel_out), 84 | .h_sync_signal(H_SYNC), //h_sync_signal), 85 | .v_sync_signal(V_SYNC), //v_sync_signal) 86 | ); 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile borrowed from https://github.com/cliffordwolf/icestorm/blob/master/examples/icestick/Makefile 2 | # 3 | # The following license is from the icestorm project and specifically applies to this file only: 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | PROJ = top 18 | VERILOG = \ 19 | ../../00_uCISC/src/processor/gpio_device.v \ 20 | ../../00_uCISC/src/processor/basic_memory_block.v \ 21 | ../../00_uCISC/src/processor/spi_flash_device.v \ 22 | ../../00_uCISC/src/processor/i2c_device.v \ 23 | ../../00_uCISC/src/processor/memory_block.v \ 24 | ../../00_uCISC/src/processor/effect_decoder.v \ 25 | ../../00_uCISC/src/processor/alu.v \ 26 | ../../00_uCISC/src/processor/dff.v \ 27 | ../../00_uCISC/src/processor/cpu.v \ 28 | ../src/gk110/gk110.v \ 29 | ../../00_uCISC/src/ice40/pll.v \ 30 | ./top.v 31 | 32 | PIN_DEF = pins.pcf 33 | DEVICE = lp8k 34 | 35 | all: $(PROJ).rpt $(PROJ).bin 36 | 37 | %.blif: %.v 38 | yosys -p 'synth_ice40 -blif $@' $(VERILOG) 39 | 40 | %.asc: $(PIN_DEF) %.blif 41 | arachne-pnr -d 8k -P cm81 -o $@ -p $^ 42 | 43 | %.bin: %.asc 44 | icepack $< $@ 45 | 46 | %.rpt: %.asc 47 | icetime -d $(DEVICE) -mtr $@ $< 48 | 49 | %_tb: %_tb.v %.v 50 | iverilog -o $@ $^ 51 | 52 | %_tb.vcd: %_tb 53 | vvp -N $< +vcd=$@ 54 | 55 | %_syn.v: %.blif 56 | yosys -p 'read_blif -wideports $^; write_verilog $@' 57 | 58 | %_syntb: %_tb.v %_syn.v 59 | iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` 60 | 61 | %_syntb.vcd: %_syntb 62 | vvp -N $< +vcd=$@ 63 | 64 | prog: $(PROJ).bin 65 | tinyprog -p $< 66 | 67 | sudo-prog: $(PROJ).bin 68 | @echo 'Executing prog as root!!!' 69 | sudo tinyprog -p $< 70 | 71 | clean: 72 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin 73 | 74 | .SECONDARY: 75 | .PHONY: all prog clean 76 | -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 4e40 0400 4a40 1400 01c0 000c 41c0 0000 41c0 0800 41c0 0000 41c0 0000 2 | 0040 002e 01c0 0006 414a 0800 10c0 0000 41c0 0000 41c0 0400 4145 0004 41c0 0004 3 | 4a40 2000 4a72 5000 0010 fffe 01c0 000c 41c0 0000 11c0 0004 41c0 0001 11c0 0005 4 | 0040 000e 414b 0001 0000 0008 4a4a 2001 414a 2100 0040 ffe8 4040 0000 41c0 0070 5 | 417a 2000 4112 0002 417a 4000 4112 0004 1440 0000 1640 0001 1740 0003 41c0 0100 6 | 2340 0000 464a 0001 474a 0001 414b 0001 0010 fff8 4440 0070 10c0 0006 -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/prog.hex.a.hex: -------------------------------------------------------------------------------- 1 | 4540 4e40 4a40 01c0 41c0 41c0 41c0 41c0 0040 2 | 01c0 414a 10c0 41c0 41c0 4145 41c0 4a40 3 | 4a72 0010 01c0 41c0 11c0 41c0 11c0 0040 4 | 414b 0000 4a4a 414a 0040 4040 41c0 417a 5 | 4112 417a 4112 1440 1640 1740 41c0 2340 6 | 464a 474a 414b 0010 4440 10c0 -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/prog.hex.b.hex: -------------------------------------------------------------------------------- 1 | 0000 0400 1400 000c 0000 0800 0000 0000 2 | 002e 0006 0800 0000 0000 0400 0004 0004 3 | 2000 5000 fffe 000c 0000 0004 0001 0005 4 | 000e 0001 0008 2001 2100 ffe8 0000 0070 5 | 2000 0002 4000 0004 0000 0001 0003 0100 6 | 0000 0001 0001 0001 fff8 0070 0006 -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | iverilog -o test_bench \ 5 | test/defines.v \ 6 | src/dff.v test/dff_tb.v 7 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 8 | echo "Found $FAILURES failures in dff_tb.v." 9 | 10 | iverilog -o test_bench \ 11 | test/defines.v \ 12 | src/memory_block.v test/memory_block_tb.v 13 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 14 | echo "Found $FAILURES failures in memory_block_tb.v." 15 | 16 | iverilog -o test_bench \ 17 | test/defines.v \ 18 | src/alu.v test/alu_tb.v 19 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 20 | echo "Found $FAILURES failures in alu_tb.v." 21 | 22 | iverilog -o test_bench \ 23 | test/defines.v \ 24 | src/effect_decoder.v test/effect_decoder_tb.v 25 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 26 | echo "Found $FAILURES failures in effect_decoder_tb.v." 27 | 28 | iverilog -o test_bench \ 29 | test/defines.v \ 30 | src/uart_tx.v test/uart_tx_tb.v 31 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 32 | echo "Found $FAILURES failures in uart_tx_tb.v." 33 | 34 | iverilog -o test_bench \ 35 | test/defines.v \ 36 | src/alu.v \ 37 | src/dff.v \ 38 | src/effect_decoder.v \ 39 | src/memory_block.v \ 40 | src/parallel_buffer.v \ 41 | src/uart_tx.v \ 42 | src/uart_rx.v \ 43 | src/uart_device.v \ 44 | src/devices.v \ 45 | src/cpu.v test/cpu_tb.v 46 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 47 | echo "Found $FAILURES failures in cpu_tb.v." 48 | 49 | #iverilog -o test_bench \ 50 | # test/defines.v \ 51 | # src/parallel_buffer.v \ 52 | # src/uart_tx.v \ 53 | # src/uart_device.v test/uart_device_tb.v 54 | #FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 55 | #echo "Found $FAILURES failures in uart_device_tb.v." 56 | 57 | iverilog -o test_bench \ 58 | test/defines.v \ 59 | src/uart_rx.v test/uart_rx_tb.v 60 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 61 | echo "Found $FAILURES failures in uart_rx_tb.v." 62 | -------------------------------------------------------------------------------- /hardware/01_GK110/ICE40/top.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokthis/ucisc/3c40a288d26409a64cf192b4cbad135579a4e0ac/hardware/01_GK110/ICE40/top.bin -------------------------------------------------------------------------------- /hardware/01_GK110/src/bootloader/load.ucisc: -------------------------------------------------------------------------------- 1 | # Defines the constants needed by the standard bootloader to load 2 | # code from the user space on the SPI flash 3 | # 4 | # Compile command (from hardware/01_GK110 project directory): 5 | # ucisc -c src/bootloader/load.ucisc \ 6 | # ../../app/core/bootloader.ucisc \ 7 | # ../../app/lib/mem_copy.ucisc > ICE40/prog.hex 8 | 9 | # Execution starts at address %0000 10 | var val.start/%0000 11 | 12 | # Safe bootloader run address is %0400. The bootloader copies itself 13 | # here to load the code from the flash device without overwriting itself 14 | var val.bootloaderRunAddress/%800 15 | 16 | # The flash device is device location 64 (%40) 17 | # The control block is located at %400 18 | var val.flashDevice/%400 19 | 20 | # Configures the number of blocks to load. This should not be enough blocks 21 | # to overwrite the bootloaderRunAddress 22 | var val.loadBlockCount/4 23 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input [15:0] source, 3 | input [15:0] destination, 4 | input [3:0] op_code, 5 | input [15:0] flags, 6 | output [15:0] result_out, 7 | output overflow, 8 | output carry 9 | ); 10 | 11 | wire [31:0] mult_result = source * destination; 12 | 13 | wire [31:0] signed_shift_destination = { {16{flags[8] & destination[15]}}, destination }; 14 | assign result_out = result[15:0]; 15 | assign carry = result[16]; 16 | assign overflow = carry; 17 | wire [16:0] result = 18 | //Bit operations 19 | op_code == 4'h0 ? source : // Copy 20 | op_code == 4'h1 ? source & destination : // AND 21 | op_code == 4'h2 ? source | destination : // OR 22 | op_code == 4'h3 ? source ^ destination : // XOR 23 | op_code == 4'h4 ? ~source : // inverse 24 | 25 | //Shift operations 26 | op_code == 4'h5 ? destination << source : // Shift left 27 | // shift signed/unsigned by sign flag 28 | op_code == 4'h6 ? source > 16'hF ? {16{flags[8] & destination[15]}} : signed_shift_destination >> source[3:0] : 29 | op_code == 4'h7 ? { source[7:0], source[15:8] } : // Swap 30 | op_code == 4'h8 ? { source[15:8], 8'h00 } : // High byte 31 | op_code == 4'h9 ? { 8'h00, source[7:0] } : // Low byte 32 | 33 | op_code == 4'hA ? destination + source : // Add 34 | op_code == 4'hB ? destination - source : // Subtract 35 | op_code == 4'hC ? mult_result[15:0] : // Multiply 36 | op_code == 4'hD ? mult_result[31:16] : // Multiply upper word 37 | op_code == 4'hE ? destination + source + flags[2] : // Add with carry 38 | 0; // TBD 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/devices.v: -------------------------------------------------------------------------------- 1 | module devices ( 2 | input ref_clock, 3 | input cpu_clock, 4 | input write_enable, 5 | input [15:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output reg [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | wire control = address[15:12] == 4'h0; 14 | wire [7:0] target_device = control ? address[11:4] : address[15:8]; 15 | 16 | always @(posedge cpu_clock) begin 17 | data_out <= 18 | target_device == 8'h02 ? uart_data_out : 19 | target_device == 8'h10 ? 16'h0 : //graphics_data_out : 20 | 16'h0; 21 | end 22 | 23 | wire [15:0] uart_data_out; 24 | uart_device #(.DEVICE_ID(16'h100)) uart_device( 25 | .clock(cpu_clock), 26 | .write_enable(write_enable & target_device == 8'h2), 27 | .control(control), 28 | .address(address[7:0]), 29 | .data_in(data_in), 30 | .rx(rx), 31 | .data_out(uart_data_out), 32 | .tx(tx), 33 | .peek(peek) 34 | ); 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/dff.v: -------------------------------------------------------------------------------- 1 | module dff( 2 | input clock, 3 | input [WIDTH-1:0] d, 4 | input async_reset, 5 | input enable, 6 | output reg [WIDTH-1:0] q 7 | ); 8 | parameter WIDTH = 1; 9 | parameter INIT = {WIDTH{1'b0}}; 10 | 11 | initial q = INIT; 12 | 13 | always @ (posedge clock or posedge async_reset) 14 | if (async_reset) begin 15 | q <= INIT; 16 | end else if (enable == 1) begin 17 | q <= d; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder ( 2 | input [15:0] flags, 3 | input [2:0] effect, 4 | output store 5 | ); 6 | assign store = 7 | effect == 3'h0 ? flags[0] : 8 | effect == 3'h1 ? ~flags[0] : 9 | effect == 3'h2 ? flags[1] : 10 | effect == 3'h3 ? ~flags[1] & ~flags[0] : 11 | effect == 3'h4 ? 1 : 12 | effect == 3'h5 ? flags[3] : 13 | effect == 3'h6 ? flags[4] : 14 | 0; 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/gpio_device.v: -------------------------------------------------------------------------------- 1 | module gpio_device( 2 | input cpu_clock, 3 | input write_enable, 4 | input is_control, 5 | input [7:0] short_address, 6 | input [15:0] cpu_data_in, 7 | output [15:0] cpu_data_out, 8 | input [63:0] gpio_in, 9 | output [63:0] gpio_out, 10 | output [63:0] gpio_config, 11 | ); 12 | parameter PINS = 16; 13 | parameter DEVICE_ID = 16'h0; 14 | parameter DEVICE_TYPE = 8'h8; 15 | 16 | wire [5:0] pin_count = PINS - 1; 17 | 18 | reg [63:0] config_reg = 64'h0; 19 | assign gpio_config = config_reg; 20 | reg [63:0] outputs = 64'h0; 21 | assign gpio_out = (config_reg & outputs) | (~config_reg & gpio_in); 22 | 23 | wire control_write = is_control & write_enable; 24 | wire [3:0] control_address = short_address[3:0]; 25 | 26 | wire [7:0] flags = { pin_count, 2'h0 }; 27 | wire [15:0] control_read = 28 | control_address == 4'h0 ? DEVICE_ID : 29 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 30 | control_address == 4'h2 ? 16'h0 : 31 | control_address == 4'h3 ? 16'h0 : 32 | control_address == 4'h4 ? gpio_config[15:0] : 33 | control_address == 4'h5 ? gpio_config[31:16]: 34 | control_address == 4'h6 ? gpio_config[47:32]: 35 | control_address == 4'h7 ? gpio_config[63:48]: 36 | control_address == 4'h8 ? outputs[15:0] : 37 | control_address == 4'h9 ? outputs[31:0] : 38 | control_address == 4'hA ? outputs[47:32] : 39 | control_address == 4'hB ? outputs[63:48] : 40 | control_address == 4'hC ? gpio_out[15:0] : 41 | control_address == 4'hD ? gpio_out[31:16] : 42 | control_address == 4'hE ? gpio_out[47:32] : 43 | control_address == 4'hF ? gpio_out[63:48] : 16'h0; 44 | 45 | assign cpu_data_out = is_control ? control_read : 16'h0; 46 | always @(posedge cpu_clock) begin 47 | if(control_write) begin 48 | if(control_address == 4'h4) 49 | config_reg[15:0] <= cpu_data_in; 50 | else if(control_address == 4'h5) 51 | config_reg[31:16] <= cpu_data_in; 52 | else if(control_address == 4'h6) 53 | config_reg[47:32] <= cpu_data_in; 54 | else if(control_address == 4'h7) 55 | config_reg[63:48] <= cpu_data_in; 56 | else if(control_address == 4'h8) 57 | outputs[15:0] <= cpu_data_in; 58 | else if(control_address == 4'h9) 59 | outputs[31:16] <= cpu_data_in; 60 | else if(control_address == 4'hA) 61 | outputs[47:32] <= cpu_data_in; 62 | else if(control_address == 4'hB) 63 | outputs[63:48] <= cpu_data_in; 64 | end 65 | end 66 | endmodule 67 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/memory_block.v: -------------------------------------------------------------------------------- 1 | module memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [WIDTH-1:0] read_address, 5 | input [WIDTH-1:0] write_address, 6 | input [15:0] data_in, 7 | output [15:0] data_out, 8 | output reg [15:0] data_out_a, 9 | output reg [15:0] data_out_b, 10 | output reg primary_out_select 11 | ); 12 | 13 | parameter WIDTH = 15; 14 | parameter mem_depth = 1 << (WIDTH - 1); 15 | parameter MEM_INIT_FILEA = "prog.hex.a.hex"; 16 | parameter MEM_INIT_FILEB = "prog.hex.b.hex"; 17 | 18 | reg [15:0] memA[mem_depth-1:0]; 19 | reg [15:0] memB[mem_depth-1:0]; 20 | 21 | initial begin 22 | $readmemh(MEM_INIT_FILEA, memA); 23 | $readmemh(MEM_INIT_FILEB, memB); 24 | end 25 | 26 | always@(posedge clock) begin 27 | primary_out_select <= read_address[0]; 28 | end 29 | assign data_out = primary_out_select ? data_out_b : data_out_a; 30 | 31 | wire [WIDTH-2:0] readA = read_address[0] ? read_address[WIDTH-1:1] + 1 : read_address[WIDTH-1:1]; 32 | always @(posedge clock) begin 33 | data_out_a <= memA[readA]; 34 | 35 | if(write_enable & ~write_address[0]) 36 | memA[write_address[WIDTH-1:1]] <= data_in; 37 | end 38 | 39 | wire [WIDTH-2:0] readB = read_address[WIDTH-1:1]; 40 | always @(posedge clock) begin 41 | data_out_b <= memB[readB]; 42 | 43 | if(write_enable & write_address[0]) 44 | memB[write_address[WIDTH-1:1]] <= data_in; 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/parallel_buffer.v: -------------------------------------------------------------------------------- 1 | module parallel_buffer( 2 | input clock, 3 | input [WIDTH-1:0] data_in, 4 | input write_in, 5 | input next_ready, 6 | output write_ready, 7 | output reg [WIDTH-1:0] data_out, 8 | output reg write_out 9 | ); 10 | parameter WIDTH = 8; 11 | initial write_out = 0; 12 | 13 | assign write_ready = ~write_out | next_ready; 14 | 15 | always @(posedge clock) begin 16 | if (write_ready & write_in) begin 17 | data_out <= data_in; 18 | write_out <= 1'b1; 19 | end else if (write_out & next_ready) begin 20 | data_out <= 0; 21 | write_out <= 1'b0; 22 | end 23 | end 24 | endmodule -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/uart_device.v: -------------------------------------------------------------------------------- 1 | module uart_device( 2 | input clock, 3 | input write_enable, 4 | input control, 5 | input [7:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | assign peek = control_read; 14 | 15 | parameter DEVICE_ID = 16'h0; 16 | parameter DEVICE_TYPE = 8'h4; 17 | 18 | wire control_write = control & write_enable; 19 | wire [3:0] control_address = address[3:0]; 20 | wire [7:0] rx_data_out; 21 | wire rx_data_ready; 22 | 23 | wire [15:0] control_read = 24 | control_address == 4'h0 ? DEVICE_ID : 25 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 26 | control_address == 4'h2 ? baud_clock_divider : 27 | control_address == 4'h4 ? { 8'h0, rx_data_out } : 28 | 16'h0; 29 | 30 | assign data_out = control ? control_read : 16'h0; 31 | 32 | wire in_progress = ~write_ready | ~ready_p1p2 | ~tx_ready; 33 | wire [7:0] flags = { 4'h1, 1'b0, in_progress, rx_data_ready, write_ready }; 34 | 35 | reg [15:0] baud_clock_divider; 36 | initial baud_clock_divider = 16'h446; // 115200 baud 37 | 38 | wire buffer_write_en = control_write & control_address == 4'h3; 39 | 40 | always @(posedge clock) begin 41 | if (control_write & control_address == 4'h2) 42 | baud_clock_divider <= data_in; 43 | end 44 | 45 | wire write_p1p2; 46 | wire ready_p1p2; 47 | wire [7:0] data_p1p2; 48 | wire tx_ready; 49 | wire [7:0] tx_data; 50 | wire tx_write; 51 | 52 | wire write_ready; 53 | parallel_buffer #(.WIDTH(8)) pb1( 54 | .clock(clock), 55 | .data_in(data_in[7:0]), 56 | .write_in(buffer_write_en), 57 | .next_ready(ready_p1p2), 58 | .write_ready(write_ready), 59 | .data_out(data_p1p2), 60 | .write_out(write_p1p2) 61 | ); 62 | 63 | parallel_buffer #(.WIDTH(8)) pb2( 64 | .clock(clock), 65 | .data_in(data_p1p2), 66 | .write_in(write_p1p2), 67 | .next_ready(tx_ready), 68 | .write_ready(ready_p1p2), 69 | .data_out(tx_data), 70 | .write_out(tx_write) 71 | ); 72 | 73 | uart_tx uart_tx( 74 | .clock(clock), 75 | .clock_divider(baud_clock_divider), 76 | .data_in(tx_data), 77 | .write_en(tx_write), 78 | .data_ready(tx_ready), 79 | .tx(tx) 80 | ); 81 | 82 | wire [15:0] rx_buffer_out; 83 | 84 | uart_rx uart_rx( 85 | .clock(clock), 86 | .clock_divider(baud_clock_divider), 87 | .read_en(control_address == 4'h4 & control_write), 88 | .rx(rx), 89 | .data_ready(rx_data_ready), 90 | .data_out(rx_data_out) 91 | ); 92 | endmodule 93 | -------------------------------------------------------------------------------- /hardware/01_GK110/src/processor_old/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input [WIDTH-1:0] data_in, 5 | input write_en, 6 | output data_ready, 7 | output tx 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | reg [15:0] clock_count = 16'h0; 12 | reg [WIDTH+1:0] data = 10'h0; 13 | reg [3:0] shift_remaining = 4'h0; 14 | assign tx = data_ready | data[0]; 15 | assign data_ready = shift_remaining == 0; 16 | 17 | always @(posedge clock) begin 18 | if (data_ready & write_en) begin 19 | data <= { 1'b1, data_in, 1'b0 }; 20 | shift_remaining <= WIDTH + 2; 21 | clock_count <= 0; 22 | end else if (~data_ready) begin 23 | if (clock_count == clock_divider) begin 24 | shift_remaining <= shift_remaining - 1'b1; 25 | data <= { 2'b1, data[WIDTH:1] }; 26 | clock_count <= 16'h0; 27 | end else begin 28 | clock_count <= clock_count + 1'b1; 29 | end 30 | end 31 | end 32 | endmodule -------------------------------------------------------------------------------- /hardware/ecp5_reference/Makefile: -------------------------------------------------------------------------------- 1 | TRELLIS?=/usr/share/trellis 2 | PROJ = ecp5_reference 3 | VERILOG := top.v $(wildcard src/*.v) 4 | TESTS := $(basename $(wildcard **/*_tb.v)) 5 | 6 | PIN_DEF = ecp5_5g_eval.lpf 7 | DEVICE = um5g-85k 8 | FREQ_TARGET = 50 9 | 10 | all: prog 11 | 12 | $(PROJ).json: $(VERILOG) #firmware.hex 13 | yosys -p "synth_ecp5 -json $@ -top top" $(VERILOG) 14 | 15 | $(PROJ)_out.config: $(PROJ).json $(PIN_DEF) 16 | nextpnr-ecp5 --json $(PROJ).json --lpf $(PIN_DEF) --textcfg $@ --$(DEVICE) --freq $(FREQ_TARGET) --package CABGA381 17 | 18 | $(PROJ).svf: $(PROJ)_out.config 19 | ecppack --svf-rowsize 100000 --svf $(PROJ).svf $< $@ 20 | 21 | prog: $(PROJ).svf 22 | openocd -f ${TRELLIS}/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf $<; exit" 23 | 24 | clean: 25 | rm -f $(PROJ).json $(PROJ)_out.config $(PROJ).svf **/*.v.iverilog* 26 | 27 | verify: $(TESTS) 28 | @echo "Tests complete." 29 | 30 | $(TESTS): %: %.v.iverilog 31 | 32 | ./test/%.v.iverilog: test/%.v 33 | @iverilog -o $@.out test/defines.v $(VERILOG) $^ 34 | @vvp $@.out > $@.results 35 | @if grep "ASSERTION FAILED" $@.results; \ 36 | then echo "Tests failed - $^"; echo "Run 'vvp $@.out' for results"; exit 1; \ 37 | else echo "Tests passed - $^"; \ 38 | fi 39 | 40 | .SECONDARY: 41 | .PHONY: all prog clean 42 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/README.md: -------------------------------------------------------------------------------- 1 | # uCISC Hardware Implementation 2 | 3 | The reference hardware implementation uses [project icestorm](http://www.clifford.at/icestorm/) 4 | to target the [TinyFPGA Bx board](https://tinyfpga.com/). As of this writing, 5 | the CPU has most of the functionality in the specs. It is able to do basic 6 | animations with LEDs (See [knight.ucisc](../examples/knight.ucisc)) and compute 7 | [fibonacci numbers](../examples/fib.ucisc). The contents of pc and r1 are sent 8 | to output pins you can hook up to LEDs to see the results (See 9 | [reference/top.v](reference/top.v) for the pinout - don't forget current 10 | limiting resistors on your LEDs). 11 | 12 | #### Basic Architecture 13 | 14 | The CPU is a 4 stage reference implementation broken up into the following 15 | stages: 16 | 17 | * Stage 0: Store result, load next instruction from memory 18 | * Stage 1: Load immediate from memory 19 | * Stage 2: Load source value from memory, or compute source from registers 20 | * Stage 3: Load dest value from memory, or compute dest from registers 21 | 22 | It has all 6 general purpose registers. 23 | 24 | Not implemented: 25 | * Manipulating the flags register other than as a result of the ALU calculation. 26 | * Manipulating the interrupt register 27 | * Memory banking for devices 28 | 29 | #### Usage 30 | 31 | 1. Follow the [project icestorm](http://www.clifford.at/icestorm/) install 32 | instructions for the yosys toolchain. 33 | 34 | 2. Compile your uCISC code to reference/prog.hex. You can use the 35 | [uCISC kotlin emulator](https://github.com/grokthis/ucisc-kotlin) for this. If 36 | you follow the install instructions there, you can run something like 37 | `ucisc -c > reference/prog.hex` to compile your code. 38 | 39 | 3. From the reference directory, do `make clean` and `make prog` with the 40 | TinyFPGA Bx board plugged into your computer. Make sure the bootloader on the 41 | FPGA is running. You may need `make sudo-prog` if your user doesn't have 42 | permissions to connect to the board. 43 | 44 | Note: You will want to hook a reset button to pin 2 with a pull down resistor. 45 | Setting reset to 3.3v will start the program over. The bootstrap process isn't 46 | as clean as I would like and sometimes program start doesn't work immediately 47 | after bootstrap and you need to reset it once. I should be able to work this 48 | out in a future release. 49 | 50 | #### Tests 51 | 52 | Install [Icarus Verilog](http://iverilog.icarus.com/) to run the tests. Then, from 53 | the reference directory, run `./run_tests` to run all tests. Note any warnings, 54 | compile errors or test failures in the output. 55 | 56 | #### Status 57 | 58 | Currently, the implementation takes about 25-35% of the resources on the 59 | Bx board, not including BRAMs of which I use all 32. I have not included 60 | devices or division in the ALU yet. In theory there is room for 2 CPUs with 61 | 4k x 16 block memory each and a couple of simple devices if you leave out 62 | the division opcode. 63 | 64 | I have successfully run at a full 16MHz without division and 8MHz with, but 65 | I may not have hit the critical long path yet with my limited testing. Time 66 | will tell, though fib(24) does push a lot of additions and memory operations 67 | through the processor. -------------------------------------------------------------------------------- /hardware/ecp5_reference/ecp5_5g_eval.lpf: -------------------------------------------------------------------------------- 1 | LOCATE COMP "CLK12" SITE "A10"; 2 | IOBUF PORT "CLK12" IO_TYPE=LVCMOS33; 3 | 4 | LOCATE COMP "UART_TX" SITE "A14"; 5 | LOCATE COMP "UART_RX" SITE "B10"; 6 | IOBUF PORT "UART_TX" IO_TYPE=LVCMOS33; 7 | IOBUF PORT "UART_RX" IO_TYPE=LVCMOS33; 8 | 9 | LOCATE COMP "DIP1" SITE "J1"; 10 | LOCATE COMP "DIP2" SITE "H1"; 11 | LOCATE COMP "DIP3" SITE "K1"; 12 | LOCATE COMP "DIP4" SITE "E15"; 13 | LOCATE COMP "DIP5" SITE "D16"; 14 | LOCATE COMP "DIP6" SITE "B16"; 15 | LOCATE COMP "DIP7" SITE "C16"; 16 | LOCATE COMP "DIP8" SITE "A16"; 17 | IOBUF PORT "DIP1" IO_TYPE=LVCMOS33; 18 | IOBUF PORT "DIP2" IO_TYPE=LVCMOS33; 19 | IOBUF PORT "DIP3" IO_TYPE=LVCMOS33; 20 | IOBUF PORT "DIP4" IO_TYPE=LVCMOS33; 21 | IOBUF PORT "DIP5" IO_TYPE=LVCMOS33; 22 | IOBUF PORT "DIP6" IO_TYPE=LVCMOS33; 23 | IOBUF PORT "DIP7" IO_TYPE=LVCMOS33; 24 | IOBUF PORT "DIP8" IO_TYPE=LVCMOS33; 25 | 26 | LOCATE COMP "SW2" SITE "G2"; 27 | IOBUF PORT "SW2" IO_TYPE=LVCMOS33; 28 | 29 | LOCATE COMP "LED[0]" SITE "A13"; 30 | LOCATE COMP "LED[1]" SITE "A12"; 31 | LOCATE COMP "LED[2]" SITE "B19"; 32 | LOCATE COMP "LED[3]" SITE "A18"; 33 | LOCATE COMP "LED[4]" SITE "B18"; 34 | LOCATE COMP "LED[5]" SITE "C17"; 35 | LOCATE COMP "LED[6]" SITE "A17"; 36 | LOCATE COMP "LED[7]" SITE "B17"; 37 | IOBUF PORT "LED[0]" IO_TYPE=LVCMOS25; 38 | IOBUF PORT "LED[1]" IO_TYPE=LVCMOS25; 39 | IOBUF PORT "LED[2]" IO_TYPE=LVCMOS25; 40 | IOBUF PORT "LED[3]" IO_TYPE=LVCMOS25; 41 | IOBUF PORT "LED[4]" IO_TYPE=LVCMOS25; 42 | IOBUF PORT "LED[5]" IO_TYPE=LVCMOS25; 43 | IOBUF PORT "LED[6]" IO_TYPE=LVCMOS25; 44 | IOBUF PORT "LED[7]" IO_TYPE=LVCMOS25; 45 | 46 | LOCATE COMP "PIXEL[0]" SITE "K4"; 47 | LOCATE COMP "PIXEL[1]" SITE "D14"; 48 | LOCATE COMP "PIXEL[2]" SITE "P1"; 49 | LOCATE COMP "PIXEL[3]" SITE "C14"; 50 | LOCATE COMP "PIXEL[4]" SITE "L1"; 51 | LOCATE COMP "PIXEL[5]" SITE "E12"; 52 | LOCATE COMP "PIXEL[6]" SITE "C12"; 53 | LOCATE COMP "PIXEL[7]" SITE "E11"; 54 | LOCATE COMP "PIXEL[8]" SITE "B20"; 55 | LOCATE COMP "PIXEL[9]" SITE "C15"; 56 | LOCATE COMP "PIXEL[10]" SITE "D15"; 57 | LOCATE COMP "PIXEL[11]" SITE "L5"; 58 | LOCATE COMP "PIXEL[12]" SITE "K3"; 59 | LOCATE COMP "PIXEL[13]" SITE "J5"; 60 | LOCATE COMP "PIXEL[14]" SITE "G1"; 61 | LOCATE COMP "PIXEL[15]" SITE "F1"; 62 | LOCATE COMP "PIXEL_CLK" SITE "B10"; 63 | LOCATE COMP "H_SYNC" SITE "E7"; 64 | LOCATE COMP "V_SYNC" SITE "A11"; 65 | 66 | IOBUF PORT "PIXEL[0]" IO_TYPE=LVCMOS33; 67 | IOBUF PORT "PIXEL[1]" IO_TYPE=LVCMOS33; 68 | IOBUF PORT "PIXEL[2]" IO_TYPE=LVCMOS33; 69 | IOBUF PORT "PIXEL[3]" IO_TYPE=LVCMOS33; 70 | IOBUF PORT "PIXEL[4]" IO_TYPE=LVCMOS33; 71 | IOBUF PORT "PIXEL[5]" IO_TYPE=LVCMOS33; 72 | IOBUF PORT "PIXEL[6]" IO_TYPE=LVCMOS33; 73 | IOBUF PORT "PIXEL[7]" IO_TYPE=LVCMOS33; 74 | IOBUF PORT "PIXEL[8]" IO_TYPE=LVCMOS33; 75 | IOBUF PORT "PIXEL[9]" IO_TYPE=LVCMOS33; 76 | IOBUF PORT "PIXEL[10]" IO_TYPE=LVCMOS33; 77 | IOBUF PORT "PIXEL[11]" IO_TYPE=LVCMOS33; 78 | IOBUF PORT "PIXEL[12]" IO_TYPE=LVCMOS33; 79 | IOBUF PORT "PIXEL[13]" IO_TYPE=LVCMOS33; 80 | IOBUF PORT "PIXEL[14]" IO_TYPE=LVCMOS33; 81 | IOBUF PORT "PIXEL[15]" IO_TYPE=LVCMOS33; 82 | IOBUF PORT "PIXEL_CLK" IO_TYPE=LVCMOS33; 83 | IOBUF PORT "H_SYNC" IO_TYPE=LVCMOS33; 84 | IOBUF PORT "V_SYNC" IO_TYPE=LVCMOS33; 85 | 86 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 4d40 0020 4e40 1000 91c9 0001 417b 0004 0010 0000 4640 1000 4740 1000 2 | 767b 0000 0000 0018 7740 ffff 3a40 0000 ee40 0001 4e7b 1100 0020 0004 4e40 1000 3 | 4971 1100 0000 0008 3940 3000 477b 0800 4700 1000 4971 1200 0000 000a 92c0 0004 4 | 4940 4000 467b 0800 4600 1000 0040 ffda -------------------------------------------------------------------------------- /hardware/ecp5_reference/prog.hex.a.hex: -------------------------------------------------------------------------------- 1 | 4540 4d40 4e40 91c9 417b 0010 4640 4740 767b 2 | 0000 7740 3a40 ee40 4e7b 0020 4e40 4971 3 | 0000 3940 477b 4700 4971 0000 92c0 4940 4 | 467b 4600 0040 -------------------------------------------------------------------------------- /hardware/ecp5_reference/prog.hex.b.hex: -------------------------------------------------------------------------------- 1 | 0000 0020 1000 0001 0004 0000 1000 1000 2 | 0000 0018 ffff 0000 0001 1100 0004 1000 3 | 1100 0008 3000 0800 1000 1200 000a 0004 4 | 4000 0800 1000 ffda -------------------------------------------------------------------------------- /hardware/ecp5_reference/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | iverilog -o test_bench \ 5 | test/defines.v \ 6 | src/dff.v test/dff_tb.v 7 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 8 | echo "Found $FAILURES failures in dff_tb.v." 9 | 10 | iverilog -o test_bench \ 11 | test/defines.v \ 12 | src/memory_block.v test/memory_block_tb.v 13 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 14 | echo "Found $FAILURES failures in memory_block_tb.v." 15 | 16 | iverilog -o test_bench \ 17 | test/defines.v \ 18 | src/alu.v test/alu_tb.v 19 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 20 | echo "Found $FAILURES failures in alu_tb.v." 21 | 22 | iverilog -o test_bench \ 23 | test/defines.v \ 24 | src/effect_decoder.v test/effect_decoder_tb.v 25 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 26 | echo "Found $FAILURES failures in effect_decoder_tb.v." 27 | 28 | iverilog -o test_bench \ 29 | test/defines.v \ 30 | src/uart_tx.v test/uart_tx_tb.v 31 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 32 | echo "Found $FAILURES failures in uart_tx_tb.v." 33 | 34 | iverilog -o test_bench \ 35 | test/defines.v \ 36 | src/alu.v \ 37 | src/dff.v \ 38 | src/effect_decoder.v \ 39 | src/memory_block.v \ 40 | src/parallel_buffer.v \ 41 | src/uart_tx.v \ 42 | src/uart_rx.v \ 43 | src/uart_device.v \ 44 | src/devices.v \ 45 | src/cpu.v test/cpu_tb.v 46 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 47 | echo "Found $FAILURES failures in cpu_tb.v." 48 | 49 | #iverilog -o test_bench \ 50 | # test/defines.v \ 51 | # src/parallel_buffer.v \ 52 | # src/uart_tx.v \ 53 | # src/uart_device.v test/uart_device_tb.v 54 | #FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 55 | #echo "Found $FAILURES failures in uart_device_tb.v." 56 | 57 | iverilog -o test_bench \ 58 | test/defines.v \ 59 | src/uart_rx.v test/uart_rx_tb.v 60 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 61 | echo "Found $FAILURES failures in uart_rx_tb.v." 62 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input [15:0] source, 3 | input [15:0] destination, 4 | input [3:0] op_code, 5 | input [15:0] flags, 6 | output [15:0] result_out, 7 | output overflow, 8 | output carry 9 | ); 10 | 11 | wire [31:0] mult_result = source * destination; 12 | 13 | wire [31:0] signed_shift_destination = { {16{flags[8] & destination[15]}}, destination }; 14 | assign result_out = result[15:0]; 15 | assign carry = result[16]; 16 | assign overflow = carry; 17 | wire [16:0] result = 18 | //Bit operations 19 | op_code == 4'h0 ? source : // Copy 20 | op_code == 4'h1 ? source & destination : // AND 21 | op_code == 4'h2 ? source | destination : // OR 22 | op_code == 4'h3 ? source ^ destination : // XOR 23 | op_code == 4'h4 ? ~source : // inverse 24 | 25 | //Shift operations 26 | op_code == 4'h5 ? destination << source : // Shift left 27 | // shift signed/unsigned by sign flag 28 | op_code == 4'h6 ? source > 16'hF ? {16{flags[8] & destination[15]}} : signed_shift_destination >> source[3:0] : 29 | op_code == 4'h7 ? { source[7:0], source[15:8] } : // Swap 30 | op_code == 4'h8 ? { source[15:8], 8'h00 } : // High byte 31 | op_code == 4'h9 ? { 8'h00, source[7:0] } : // Low byte 32 | 33 | op_code == 4'hA ? destination + source : // Add 34 | op_code == 4'hB ? destination - source : // Subtract 35 | op_code == 4'hC ? mult_result[15:0] : // Multiply 36 | op_code == 4'hD ? mult_result[31:16] : // Multiply upper word 37 | op_code == 4'hE ? destination + source + flags[2] : // Add with carry 38 | 0; // TBD 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/devices.v: -------------------------------------------------------------------------------- 1 | module devices ( 2 | input ref_clock, 3 | input cpu_clock, 4 | input write_enable, 5 | input [15:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output reg [15:0] data_out, 9 | output tx, 10 | output [15:0] peek, 11 | output [15:0] pixel_out, 12 | output h_sync_signal, 13 | output v_sync_signal 14 | ); 15 | 16 | wire control = address[15:12] == 4'h0; 17 | wire [7:0] target_device = control ? address[11:4] : address[15:8]; 18 | 19 | always @(posedge cpu_clock) begin 20 | data_out <= 21 | target_device == 8'h02 ? uart_data_out : 22 | target_device == 8'h10 ? 16'h0 : //graphics_data_out : 23 | 16'h0; 24 | end 25 | 26 | wire [15:0] uart_data_out; 27 | uart_device #(.DEVICE_ID(16'h100)) uart_device( 28 | .clock(cpu_clock), 29 | .write_enable(write_enable & target_device == 8'h2), 30 | .control(control), 31 | .address(address[7:0]), 32 | .data_in(data_in), 33 | .rx(rx), 34 | .data_out(uart_data_out), 35 | .tx(tx), 36 | .peek(peek) 37 | ); 38 | 39 | // wire [15:0] graphics_data_out; 40 | // vga_device vga_device( 41 | // .ref_clock(ref_clock), 42 | // .cpu_clock(cpu_clock), 43 | // .control(control), 44 | //// .write_enable(write_enable & target_device == 8'h10), 45 | // .write_enable(1'h0), 46 | //// .write_address(address[7:0]), 47 | // .write_address(8'h0), 48 | //// .data_in(data_in), 49 | // .data_in(16'h0061), 50 | // .read_enable(1'h0), 51 | // .read_address(address[7:0]), 52 | // .data_out(graphics_data_out), 53 | // .pixel_out(pixel_out), 54 | // .h_sync_signal(h_sync_signal), 55 | // .v_sync_signal(v_sync_signal) 56 | // ); 57 | 58 | endmodule 59 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/dff.v: -------------------------------------------------------------------------------- 1 | module dff( 2 | input clock, 3 | input [WIDTH-1:0] d, 4 | input async_reset, 5 | input enable, 6 | output reg [WIDTH-1:0] q 7 | ); 8 | parameter WIDTH = 1; 9 | parameter INIT = {WIDTH{1'b0}}; 10 | 11 | initial q = INIT; 12 | 13 | always @ (posedge clock or posedge async_reset) 14 | if (async_reset) begin 15 | q <= INIT; 16 | end else if (enable == 1) begin 17 | q <= d; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder ( 2 | input [15:0] flags, 3 | input [2:0] effect, 4 | output store 5 | ); 6 | assign store = 7 | effect == 3'h0 ? flags[0] : 8 | effect == 3'h1 ? ~flags[0] : 9 | effect == 3'h2 ? flags[1] : 10 | effect == 3'h3 ? ~flags[1] & ~flags[0] : 11 | effect == 3'h4 ? 1 : 12 | effect == 3'h5 ? flags[3] : 13 | effect == 3'h6 ? flags[4] : 14 | 0; 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/memory_block.v: -------------------------------------------------------------------------------- 1 | module memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [WIDTH-1:0] read_address, 5 | input [WIDTH-1:0] write_address, 6 | input [15:0] data_in, 7 | output [15:0] data_out, 8 | output reg [15:0] data_out_a, 9 | output reg [15:0] data_out_b, 10 | output reg primary_out_select 11 | ); 12 | 13 | parameter WIDTH = 15; 14 | parameter mem_depth = 1 << (WIDTH - 1); 15 | parameter MEM_INIT_FILEA = "prog.hex.a.hex"; 16 | parameter MEM_INIT_FILEB = "prog.hex.b.hex"; 17 | 18 | reg [15:0] memA[mem_depth-1:0]; 19 | reg [15:0] memB[mem_depth-1:0]; 20 | 21 | initial begin 22 | $readmemh(MEM_INIT_FILEA, memA); 23 | $readmemh(MEM_INIT_FILEB, memB); 24 | end 25 | 26 | always@(posedge clock) begin 27 | primary_out_select <= read_address[0]; 28 | end 29 | assign data_out = primary_out_select ? data_out_b : data_out_a; 30 | 31 | wire [WIDTH-2:0] readA = read_address[0] ? read_address[WIDTH-1:1] + 1 : read_address[WIDTH-1:1]; 32 | always @(posedge clock) begin 33 | data_out_a <= memA[readA]; 34 | 35 | if(write_enable & ~write_address[0]) 36 | memA[write_address[WIDTH-1:1]] <= data_in; 37 | end 38 | 39 | wire [WIDTH-2:0] readB = read_address[WIDTH-1:1]; 40 | always @(posedge clock) begin 41 | data_out_b <= memB[readB]; 42 | 43 | if(write_enable & write_address[0]) 44 | memB[write_address[WIDTH-1:1]] <= data_in; 45 | end 46 | 47 | endmodule 48 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/parallel_buffer.v: -------------------------------------------------------------------------------- 1 | module parallel_buffer( 2 | input clock, 3 | input [WIDTH-1:0] data_in, 4 | input write_in, 5 | input next_ready, 6 | output write_ready, 7 | output reg [WIDTH-1:0] data_out, 8 | output reg write_out 9 | ); 10 | parameter WIDTH = 8; 11 | initial write_out = 0; 12 | 13 | assign write_ready = ~write_out | next_ready; 14 | 15 | always @(posedge clock) begin 16 | if (write_ready & write_in) begin 17 | data_out <= data_in; 18 | write_out <= 1'b1; 19 | end else if (write_out & next_ready) begin 20 | data_out <= 0; 21 | write_out <= 1'b0; 22 | end 23 | end 24 | endmodule -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/pll.v: -------------------------------------------------------------------------------- 1 | module pll(input clki, output clko); 2 | (* ICP_CURRENT="12" *) (* LPF_RESISTOR="8" *) (* MFG_ENABLE_FILTEROPAMP="1" *) (* MFG_GMCREF_SEL="2" *) 3 | 4 | parameter CLKI_DIV = 1; 5 | parameter CLKFB_DIV = 1; 6 | parameter CLKOP_DIV = 1; 7 | 8 | EHXPLLL #( 9 | .PLLRST_ENA("DISABLED"), 10 | .INTFB_WAKE("DISABLED"), 11 | .STDBY_ENABLE("DISABLED"), 12 | .DPHASE_SOURCE("DISABLED"), 13 | .CLKOP_FPHASE(0), 14 | .CLKOP_CPHASE(11), 15 | .OUTDIVIDER_MUXA("DIVA"), 16 | .CLKOP_ENABLE("ENABLED"), 17 | .CLKOP_DIV(CLKOP_DIV), 18 | .CLKFB_DIV(CLKFB_DIV), 19 | .CLKI_DIV(CLKI_DIV), 20 | .FEEDBK_PATH("CLKOP") 21 | ) pll_i ( 22 | .CLKI(clki), 23 | .CLKFB(clko), 24 | .CLKOP(clko), 25 | .RST(1'b0), 26 | .STDBY(1'b0), 27 | .PHASESEL0(1'b0), 28 | .PHASESEL1(1'b0), 29 | .PHASEDIR(1'b0), 30 | .PHASESTEP(1'b0), 31 | .PLLWAKESYNC(1'b0), 32 | .ENCLKOP(1'b0) 33 | ); 34 | endmodule 35 | 36 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/uart_device.v: -------------------------------------------------------------------------------- 1 | module uart_device( 2 | input clock, 3 | input write_enable, 4 | input control, 5 | input [7:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | assign peek = control_read; 14 | 15 | parameter DEVICE_ID = 16'h0; 16 | parameter DEVICE_TYPE = 8'h4; 17 | 18 | wire control_write = control & write_enable; 19 | wire [3:0] control_address = address[3:0]; 20 | wire [7:0] rx_data_out; 21 | wire rx_data_ready; 22 | 23 | wire [15:0] control_read = 24 | control_address == 4'h0 ? DEVICE_ID : 25 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 26 | control_address == 4'h2 ? baud_clock_divider : 27 | control_address == 4'h4 ? { 8'h0, rx_data_out } : 28 | 16'h0; 29 | 30 | assign data_out = control ? control_read : 16'h0; 31 | 32 | wire in_progress = ~write_ready | ~ready_p1p2 | ~tx_ready; 33 | wire [7:0] flags = { 4'h1, 1'b0, in_progress, rx_data_ready, write_ready }; 34 | 35 | reg [15:0] baud_clock_divider; 36 | initial baud_clock_divider = 16'h446; // 115200 baud 37 | 38 | wire buffer_write_en = control_write & control_address == 4'h3; 39 | 40 | always @(posedge clock) begin 41 | if (control_write & control_address == 4'h2) 42 | baud_clock_divider <= data_in; 43 | end 44 | 45 | wire write_p1p2; 46 | wire ready_p1p2; 47 | wire [7:0] data_p1p2; 48 | wire tx_ready; 49 | wire [7:0] tx_data; 50 | wire tx_write; 51 | 52 | wire write_ready; 53 | parallel_buffer #(.WIDTH(8)) pb1( 54 | .clock(clock), 55 | .data_in(data_in[7:0]), 56 | .write_in(buffer_write_en), 57 | .next_ready(ready_p1p2), 58 | .write_ready(write_ready), 59 | .data_out(data_p1p2), 60 | .write_out(write_p1p2) 61 | ); 62 | 63 | parallel_buffer #(.WIDTH(8)) pb2( 64 | .clock(clock), 65 | .data_in(data_p1p2), 66 | .write_in(write_p1p2), 67 | .next_ready(tx_ready), 68 | .write_ready(ready_p1p2), 69 | .data_out(tx_data), 70 | .write_out(tx_write) 71 | ); 72 | 73 | uart_tx uart_tx( 74 | .clock(clock), 75 | .clock_divider(baud_clock_divider), 76 | .data_in(tx_data), 77 | .write_en(tx_write), 78 | .data_ready(tx_ready), 79 | .tx(tx) 80 | ); 81 | 82 | wire [15:0] rx_buffer_out; 83 | 84 | uart_rx uart_rx( 85 | .clock(clock), 86 | .clock_divider(baud_clock_divider), 87 | .read_en(control_address == 4'h4 & control_write), 88 | .rx(rx), 89 | .data_ready(rx_data_ready), 90 | .data_out(rx_data_out) 91 | ); 92 | endmodule 93 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input [WIDTH-1:0] data_in, 5 | input write_en, 6 | output data_ready, 7 | output tx 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | reg [15:0] clock_count = 16'h0; 12 | reg [WIDTH+1:0] data = 10'h0; 13 | reg [3:0] shift_remaining = 4'h0; 14 | assign tx = data_ready | data[0]; 15 | assign data_ready = shift_remaining == 0; 16 | 17 | always @(posedge clock) begin 18 | if (data_ready & write_en) begin 19 | data <= { 1'b1, data_in, 1'b0 }; 20 | shift_remaining <= WIDTH + 2; 21 | clock_count <= 0; 22 | end else if (~data_ready) begin 23 | if (clock_count == clock_divider) begin 24 | shift_remaining <= shift_remaining - 1'b1; 25 | data <= { 2'b1, data[WIDTH:1] }; 26 | clock_count <= 16'h0; 27 | end else begin 28 | clock_count <= clock_count + 1'b1; 29 | end 30 | end 31 | end 32 | endmodule -------------------------------------------------------------------------------- /hardware/ecp5_reference/src/vga.v: -------------------------------------------------------------------------------- 1 | module vga( 2 | input clk_1920_1080, 3 | input clk_1280_960, 4 | input [15:0] pixel_in, 5 | input aspect_ratio, 6 | input text_mode, 7 | input [1:0] resolution, 8 | output reg h_sync_signal, 9 | output reg v_sync_signal, 10 | output pixel_change_clk, 11 | output reg [15:0] pixel_out, 12 | output v_sync_en, 13 | output [10:0] screen_width, 14 | output [10:0] screen_height, 15 | output [2:0] pixel_width 16 | ); 17 | 18 | wire pixel_clk = aspect_ratio ? clk_1920_1080 : clk_1280_960; 19 | 20 | assign screen_width = aspect_ratio ? 11'd1920 : 11'd1280; 21 | wire [15:0] h_fp = aspect_ratio ? 16'd2008 : 16'd1360; 22 | wire [15:0] h_sync = aspect_ratio ? 16'd2052 : 16'd1496; 23 | wire [15:0] h_bp = aspect_ratio ? 16'd2200 : 16'd1712; 24 | 25 | assign screen_height = aspect_ratio ? 16'd1080 : 16'd960; 26 | wire [15:0] v_fp = aspect_ratio ? 16'd1084 : 16'd961; 27 | wire [15:0] v_sync = aspect_ratio ? 16'd1089 : 16'd964; 28 | wire [15:0] v_bp = aspect_ratio ? 16'd1125 : 16'd994; 29 | 30 | wire h_polarity = aspect_ratio ? 1'b1 : 1'b0; 31 | wire v_polarity = 1'b1; 32 | 33 | assign pixel_width = 34 | resolution == 2'h0 ? 3'h3 : 35 | resolution == 2'h1 ? 3'h2 : 36 | resolution == 2'h2 ? 3'h1 : 37 | 3'h0; 38 | 39 | reg [15:0] h_count = 16'h0; 40 | reg [15:0] v_count = 16'h0; 41 | 42 | wire h_pixel_en = h_count < screen_width; 43 | wire h_sync_en = (h_count >= h_fp) && (h_count < h_sync); 44 | 45 | wire v_pixel_en = v_count < screen_height; 46 | assign v_sync_en = (v_count >= v_fp) && (v_count < v_sync); 47 | 48 | wire pixel_out_enabled = (h_count < screen_width && v_count < screen_height); 49 | //always @(negedge pixel_clk) begin 50 | // pixel_out_enabled <= (h_count < screen_width && v_count < screen_height); 51 | //end 52 | 53 | wire [15:0] h_next = h_count + 1'b1; 54 | wire [15:0] v_next = v_count + 1'b1; 55 | 56 | reg pixel_clk_enabled; 57 | assign pixel_change_clk = pixel_clk_enabled & ~pixel_clk; 58 | 59 | always @(negedge pixel_clk) begin 60 | pixel_clk_enabled <= h_count < screen_width && v_count < screen_height; 61 | if (h_next == h_bp) begin 62 | h_count <= 16'h0; 63 | 64 | if (v_next == v_bp) 65 | v_count <= 16'h0; 66 | else begin 67 | v_count <= v_next; 68 | end 69 | end else begin 70 | h_count <= h_next; 71 | end 72 | 73 | h_sync_signal <= h_polarity ^ ~h_sync_en; 74 | v_sync_signal <= v_polarity ^ ~v_sync_en; 75 | 76 | pixel_out <= (h_pixel_en & v_pixel_en) ? pixel_in : 16'h0000; 77 | end 78 | 79 | endmodule 80 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/defines.v: -------------------------------------------------------------------------------- 1 | `define assert(signal, value) if (signal !== value) begin $display("ASSERTION FAILED in %m: signal != value"); $finish; end 2 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/dff_tb.v: -------------------------------------------------------------------------------- 1 | module dff_tb; 2 | 3 | // Setup registers for the DFF inputs 4 | reg clock; 5 | reg [15:0] d; 6 | reg a_reset; 7 | reg enable; 8 | 9 | // Setup a wire for the dff output "q" 10 | wire [15:0] q; 11 | 12 | // Instantiate the unit under test 13 | dff #(.WIDTH(16)) dff( 14 | .clock(clock), 15 | .d(d), 16 | .async_reset(a_reset), 17 | .enable(enable), 18 | .q(q) 19 | ); 20 | 21 | initial begin 22 | // Initialize standard setup 23 | clock = 0; 24 | d = 16'h0; 25 | a_reset = 0; 26 | enable = 1; 27 | 28 | #20 d = 16'hFFFF; 29 | // Should capture on positive clock edge 30 | #20 clock = 1; 31 | #1 `assert(q, 16'hFFFF); 32 | 33 | // Should not capture without positive clock edge 34 | #20 d = 16'h1111; 35 | #1 `assert(q, 16'hFFFF); 36 | #20 clock = 0; 37 | #1 `assert(q, 16'hFFFF); 38 | 39 | // Reset sets output and holds output at 0 40 | #20 a_reset = 1; 41 | #1 `assert(q, 16'h0000); 42 | #20 clock = 1; 43 | #1 `assert(q, 16'h0000); 44 | #20 a_reset = 0; 45 | #1 `assert(q, 16'h0000); 46 | 47 | // Enable held at 0 makes DFF unresponsive to clock 48 | #20 d = 16'hF42F; 49 | #1 `assert(q, 16'h0000); 50 | enable = 0; 51 | #1 `assert(q, 16'h0000); 52 | #20 clock = 0; 53 | #1 `assert(q, 16'h0000); 54 | #20 clock = 1; 55 | #1 `assert(q, 16'h0000); 56 | 57 | // Enable assertion doesn't capture input 58 | #20 enable = 1; 59 | #1 `assert(q, 16'h0000); 60 | #20 clock = 0; 61 | #1 `assert(q, 16'h0000); 62 | // Positive edge captures input 63 | #20 clock = 1; 64 | #1 `assert(q, 16'hF42F); 65 | end 66 | 67 | initial begin 68 | $monitor("clock=%d, d=%04x, async_reset=%d, enable=%d, q=%04x", clock, d, a_reset, enable, q); 69 | end 70 | endmodule 71 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/dff_tb.v.results: -------------------------------------------------------------------------------- 1 | WARNING: src/memory_block.v:18: $readmemh: Standard inconsistency, following 1364-2005. 2 | WARNING: src/memory_block.v:18: $readmemh(prog.hex): Not enough words in the file for the requested range [0:8191]. 3 | clock=0, d=0000, async_reset=0, enable=1, q=0000 4 | clock=0, d=ffff, async_reset=0, enable=1, q=0000 5 | clock=1, d=ffff, async_reset=0, enable=1, q=ffff 6 | clock=1, d=1111, async_reset=0, enable=1, q=ffff 7 | clock=0, d=1111, async_reset=0, enable=1, q=ffff 8 | clock=0, d=1111, async_reset=1, enable=1, q=0000 9 | clock=1, d=1111, async_reset=1, enable=1, q=0000 10 | clock=1, d=1111, async_reset=0, enable=1, q=0000 11 | clock=1, d=f42f, async_reset=0, enable=1, q=0000 12 | clock=1, d=f42f, async_reset=0, enable=0, q=0000 13 | clock=0, d=f42f, async_reset=0, enable=0, q=0000 14 | clock=1, d=f42f, async_reset=0, enable=0, q=0000 15 | clock=1, d=f42f, async_reset=0, enable=1, q=0000 16 | clock=0, d=f42f, async_reset=0, enable=1, q=0000 17 | clock=1, d=f42f, async_reset=0, enable=1, q=f42f 18 | -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/effect_decoder_tb.v: -------------------------------------------------------------------------------- 1 | module effect_decoder_tb; 2 | 3 | // Setup registers for the inputs 4 | reg [15:0] flags; 5 | reg [2:0] effect; 6 | 7 | // Setup a wire for the outputs 8 | wire store; 9 | 10 | // Instantiate the unit under test 11 | effect_decoder effect_decoder( 12 | .flags(flags), 13 | .effect(effect), 14 | .store(store) 15 | ); 16 | 17 | initial begin 18 | // Initialize standard setup 19 | flags = 16'h0; 20 | effect = 3'h0; 21 | 22 | #1 `assert(store, 0); 23 | // TODO Implement these tests 24 | end 25 | 26 | initial begin 27 | $monitor("flags=%04x, effect=%d, store=%x", flags, effect, store); 28 | end 29 | endmodule -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/test_prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 41c0 07ff 1540 0000 4540 0000 4640 ffff 61c0 0000 1540 0000 4540 0000 2 | 41c0 0400 17c0 0000 51c0 0000 1540 0000 4540 0000 41c0 0400 41c0 000a 5640 0001 3 | 12c0 1000 1540 0000 0040 0000 -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/test_prog.hex.a.hex: -------------------------------------------------------------------------------- 1 | 4540 41c0 1540 4540 4640 61c0 1540 4540 2 | 41c0 17c0 51c0 1540 4540 41c0 41c0 5640 3 | 12c0 1540 0040 -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/test_prog.hex.b.hex: -------------------------------------------------------------------------------- 1 | 0000 07ff 0000 0000 ffff 0000 0000 0000 2 | 0400 0000 0000 0000 0000 0400 000a 0001 3 | 1000 0000 0000 -------------------------------------------------------------------------------- /hardware/ecp5_reference/test/test_prog.ucisc: -------------------------------------------------------------------------------- 1 | # Specialized version of https://github.com/grokthis/ucisc-kotlin/tree/trunk/src/ucisc/test 2 | # designed to avoid halts and let the verilog simulator step through and verify state 3 | 4 | ##################### 5 | # Stack Setup Tests # 6 | ##################### 7 | 8 | testMaxImm: 9 | copy val 0 &stack 10 | copy val 2047 stack 0 push 11 | # expect r1 = FFFF 12 | copy r1 0 &r1 13 | # expect r1 = 2047 14 | 15 | # Begin instruction 4 16 | testMaxImmReg: 17 | copy val 0 &stack 18 | copy val 65535 &r2 19 | copy &r2 0 stack 0 push 20 | # expect r1 = FFFF 21 | copy r1 0 &r1 22 | # expect r1 = FFFF 23 | 24 | # Begin instruction 8 25 | testPopStack: 26 | copy val 0 &stack 27 | copy val 1024 stack 0 push 28 | # expect r1 = FFFF 29 | copy stack 0 &r3 pop 30 | # expect r1 = 0000 31 | copy &stack 0 stack 0 push 32 | # expect r1 = FFFF 33 | copy stack 0 &stack 34 | # expect r1 = 0000 35 | 36 | # Begin instruction 13 37 | testMemCopy1: 38 | copy val 0 &stack 39 | copy val 1024 stack 0 push 40 | # expect r1 = FFFF 41 | copy val 10 stack 0 push 42 | # expect r1 = FFFE 43 | copy &stack 1 &r2 44 | copy stack 0 r2 1 push 45 | # expect r1 = FFFE 46 | copy stack 0 &stack 47 | # expect r1 = 000A 48 | copy pc 0 pc -------------------------------------------------------------------------------- /hardware/ecp5_reference/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input CLK12, 3 | input DIP1, 4 | input DIP2, 5 | input DIP3, 6 | input DIP4, 7 | input DIP5, 8 | input DIP6, 9 | input DIP7, 10 | input DIP8, 11 | input SW2, 12 | output UART_TX, 13 | input UART_RX, 14 | // output [7:0] LED, 15 | output [15:0] PIXEL, 16 | output H_SYNC, 17 | output V_SYNC 18 | ); 19 | 20 | parameter CLOCK_DIV = 10; 21 | parameter CLOCK_MULT = 85; 22 | 23 | //assign LED[7] = ~r1[7]; 24 | //assign LED[6] = ~r1[6]; 25 | //assign LED[5] = ~r1[5]; 26 | //assign LED[4] = ~r1[4]; 27 | //assign LED[3] = ~r1[3]; 28 | //assign LED[2] = ~r1[2]; 29 | //assign LED[1] = ~r1[1]; 30 | //assign LED[0] = ~r1[0]; 31 | 32 | assign UART_TX = tx; 33 | wire rx = UART_RX; 34 | 35 | //wire [15:0] r1; 36 | wire tx; 37 | //assign LED = tx; 38 | 39 | wire ref_clock = CLK12; 40 | wire cpu_clock; 41 | pll #( 42 | .CLKI_DIV(CLOCK_DIV), 43 | .CLKFB_DIV(CLOCK_MULT), 44 | .CLKOP_DIV(1), 45 | ) 46 | pll_cpu ( 47 | .clki(CLK12), 48 | .clko(cpu_clock) 49 | ); 50 | 51 | cpu #( 52 | .CLOCK_DIV(10), 53 | .CLOCK_MULT(105) 54 | ) cpu( 55 | .clk(CLK12), 56 | .reset(0), 57 | // .r1_peek(r1), 58 | .tx(tx), 59 | .rx(rx)//, 60 | //.pixel_out(PIXEL), 61 | //.h_sync_signal(H_SYNC), 62 | //.v_sync_signal(V_SYNC) 63 | ); 64 | 65 | wire control = 1'b1; 66 | wire vga_control_we = ~SW2; 67 | wire [15:0] data_input = { 8'h0, DIP8, DIP7, DIP6, DIP5, DIP4, DIP3, DIP2, DIP1 }; 68 | 69 | wire [15:0] graphics_data_out; 70 | vga_device vga_device( 71 | .ref_clock(ref_clock), 72 | .cpu_clock(cpu_clock), 73 | .control(control), //control), 74 | // .write_enable(write_enable & target_device == 8'h10), 75 | .write_enable(vga_control_we), 76 | // .write_address(address[7:0]), 77 | .write_address(16'h0002), 78 | // .data_in(data_in), 79 | .data_in(data_input), 80 | .read_enable(1'h0), 81 | .read_address(8'h0), //address[7:0]), 82 | //.data_out(graphics_data_out), 83 | .pixel_out(PIXEL), //pixel_out), 84 | .h_sync_signal(H_SYNC), //h_sync_signal), 85 | .v_sync_signal(V_SYNC), //v_sync_signal) 86 | ); 87 | 88 | endmodule 89 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/Makefile: -------------------------------------------------------------------------------- 1 | PROJ=ucisc 2 | TRELLIS?=/usr/share/trellis 3 | VERILOG = processor_core.v instruction_decoder.v copy_decoder.v alu_decoder.v page_decoder.v effect_decoder.v alu.v register_block.v pc.v memory_block.v 4 | #VERILOG = register_block.v 5 | 6 | all: ${PROJ}.bit 7 | 8 | ${PROJ}.json: $(VERILOG) 9 | yosys -p "synth_ecp5 -json $@" $(VERILOG) 10 | 11 | ${PROJ}_out.config: ${PROJ}.json 12 | nextpnr-ecp5 --json $< --textcfg $@ --um5g-85k --package CABGA381 --lpf ecp5evn.lpf 13 | 14 | ${PROJ}.bit: ${PROJ}_out.config 15 | ecppack --svf ${PROJ}.svf $< $@ 16 | 17 | ${PROJ}.svf : ${PROJ}.bit 18 | 19 | ucisc: ${PROJ}.svf 20 | openocd -f ${TRELLIS}/misc/openocd/ecp5-evn.cfg -c "transport select jtag; init; svf $<; exit" 21 | 22 | clean: 23 | rm -f *.svf *.bit *.config *.json 24 | 25 | .PHONY: ucisc clean 26 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/alu_decoder.v: -------------------------------------------------------------------------------- 1 | module alu_decoder( 2 | input [15:0] instruction, 3 | output source_immediate, 4 | output source_memory, 5 | output [6:0] immediate, 6 | output [4:0] alu_code, 7 | output pre_increment, 8 | output post_increment, 9 | output decrement, 10 | output [2:0] source_select, 11 | output [2:0] destination_select, 12 | output destination_pc, 13 | output destination_mem, 14 | output destination_reg, 15 | output [2:0] effect 16 | ); 17 | 18 | // Controls if source of 4 is interpreted as flags or immediate 19 | assign source_immediate = 0; 20 | assign source_memory = ~source_select[2] & (source_select[0] | source_select[1]); 21 | assign alu_code = instruction[6:2]; 22 | assign decrement = sign; 23 | wire sign = instruction[13]; 24 | 25 | // whether the destination is memory or not changes how a 26 | // few things are interpreted. 27 | assign destination_mem = destination_select[0] | destination_select[1]; 28 | 29 | assign immediate = 7'b0; 30 | 31 | assign pre_increment = 0; 32 | assign post_increment = instruction[12]; 33 | 34 | assign source_select = instruction[9:7]; 35 | assign destination_select = {0,instruction[11:10]}; 36 | 37 | assign destination_pc = instruction[11] ~& instruction[10]; 38 | assign destination_reg = 0; 39 | 40 | assign effect[2] = ~post_increment & sign; 41 | assign effect[1:0] = instruction[14:13]; 42 | 43 | endmodule 44 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/copy_decoder.v: -------------------------------------------------------------------------------- 1 | module copy_decoder( 2 | input [15:0] instruction, 3 | output source_immediate, 4 | output source_memory, 5 | output [6:0] immediate, 6 | output [4:0] alu_code, 7 | output pre_increment, 8 | output post_increment, 9 | output decrement, 10 | output [2:0] source_select, 11 | output [2:0] destination_select, 12 | output destination_pc, 13 | output destination_mem, 14 | output destination_reg, 15 | output [2:0] effect 16 | ); 17 | 18 | // Controls if source of 4 is interpreted as flags or immediate 19 | assign source_immediate = 1; 20 | assign source_memory = ~source_select[2] & (source_select[0] | source_select[1]); 21 | // Copy is always ALU code 0 22 | assign alu_code = 5'b00000; 23 | // Copy always decrements, never increments 24 | assign decrement = 1; 25 | wire control = instruction[6]; 26 | 27 | // whether the destination is memory or not changes how a 28 | // few things are interpreted. 29 | assign destination_mem = ~destination_select[2] && (destination_select[0] | destination_select[1]); 30 | 31 | assign immediate = 32 | (destination_mem) ? {instruction[5],instruction[5:0]} : 33 | (~destination_mem) ? instruction[6:0]: 34 | 7'h0; 35 | 36 | assign pre_increment = destination_mem & control; 37 | assign post_increment = 0; 38 | 39 | assign source_select = instruction[9:7]; 40 | assign destination_select = instruction[12:10]; 41 | 42 | assign destination_pc = destination_select == 3'b000; 43 | assign destination_reg = destination_select[2]; 44 | 45 | assign effect[2] = 0; 46 | assign effect[1:0] = instruction[14:13]; 47 | 48 | endmodule 49 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder( 2 | input [4:0] flags, 3 | input [2:0] effect, 4 | output reg store 5 | ); 6 | 7 | wire overflow = flags[0]; 8 | wire zero = flags[2]; 9 | wire negative = flags[3]; 10 | 11 | always @* begin 12 | case (effect) 13 | // store if zero 14 | 3'h0: store = zero; 15 | // store if not zero 16 | 3'h1: store = ~zero; 17 | // store if positive 18 | 3'h2: store = zero ~| negative; 19 | // store always 20 | 3'h3: store = 1; 21 | // store if not negative (>= 0) 22 | 3'h4: store = ~negative; 23 | // store if negative 24 | 3'h5: store = negative; 25 | // store if not overflow 26 | 3'h6: store = ~overflow; 27 | // never store 28 | 3'h7: store = 0; 29 | endcase 30 | end 31 | 32 | endmodule 33 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/memory_block.v: -------------------------------------------------------------------------------- 1 | // Write clock must flip @negedge of clock to setup next address 2 | // Read + Write Timing: 3 | // t0 = @negedge clock, write_clock 4 | // t1 = @posedge clock, write_clock - write to portB if write_enabled 5 | // t2 = @negedge clock, ~write_clock - portB_out valid 6 | // t3 = @posedge clock, ~write_clock - portA_out valid 7 | module memory_block ( 8 | input clock, 9 | input write_clock, 10 | input write_enable, 11 | input [address_width-1:0] portA_address, 12 | input [address_width-1:0] portB_address, 13 | input [data_width-1:0] data_in, 14 | output reg [data_width-1:0] portA_out, 15 | output reg [data_width-1:0] portB_out 16 | ); 17 | 18 | parameter data_width = 16; 19 | parameter address_width = 10; 20 | parameter mem_depth = 1 << address_width; 21 | 22 | reg [data_width-1:0] mem[mem_depth-1:0]; 23 | 24 | wire [address_width-1:0] read_address = write_clock ? portB_address : portA_address; 25 | 26 | always@(negedge clock) begin 27 | if(~write_clock) 28 | portB_out = portA_out; 29 | end 30 | 31 | always @(posedge clock) begin 32 | portA_out <= mem[read_address]; 33 | if(write_clock && write_enable) 34 | mem[read_address] <= data_in; 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/page_decoder.v: -------------------------------------------------------------------------------- 1 | module page_decoder( 2 | input [15:0] instruction, 3 | output source_immediate, 4 | output source_memory, 5 | output [6:0] immediate, 6 | output [4:0] alu_code, 7 | output pre_increment, 8 | output post_increment, 9 | output decrement, 10 | output [2:0] source_select, 11 | output [2:0] destination_select, 12 | output destination_pc, 13 | output destination_mem, 14 | output destination_reg, 15 | output [2:0] effect 16 | ); 17 | 18 | // Controls if source of 4 is interpreted as flags or immediate 19 | assign source_immediate = 1; 20 | assign source_memory = (source_select[0] | source_select[1]); 21 | assign alu_code = 5'b0; 22 | assign decrement = 0; 23 | assign pre_increment = 0; 24 | assign post_increment = 0; 25 | assign effect[2:0] = 3'b11; 26 | assign immediate = {instruction[5], instruction[5:0]}; 27 | 28 | // whether the destination is memory or not changes how a 29 | // few things are interpreted. 30 | assign source_select = instruction[9:7]; 31 | assign destination_select = 3'b0; 32 | assign destination_pc = 0; 33 | assign destination_mem = 0; 34 | assign destination_reg = 0; 35 | 36 | endmodule 37 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/pc.v: -------------------------------------------------------------------------------- 1 | // program counter 2 | 3 | module pc( 4 | input clock, 5 | input reset, 6 | input store_enabled, 7 | input destination_pc, 8 | input [15:0] source_value, 9 | output reg [15:0] current_pc, 10 | output reg [15:0] next_pc 11 | ); 12 | 13 | wire [15:0] inc_pc = current_pc + 1; 14 | 15 | always @(negedge clock) 16 | if (reset) 17 | next_pc <= 16'h0; 18 | else if (destination_pc & store_enabled) 19 | next_pc <= source_value; 20 | else 21 | next_pc <= inc_pc; 22 | 23 | always @(posedge clock) 24 | current_pc <= next_pc; 25 | 26 | endmodule 27 | -------------------------------------------------------------------------------- /hardware/ecp5_single_IPC/register_block.v: -------------------------------------------------------------------------------- 1 | module register_block( 2 | input clock, 3 | input [15:0] pc, 4 | input source_immediate, 5 | input [6:0] immediate, 6 | input [15:0] destination_write, 7 | input [2:0] destination_select, 8 | input [2:0] source_select, 9 | input [15:0] flags_value, 10 | input set_flags, 11 | input store_value, 12 | input pre_increment, 13 | input post_increment, 14 | input decrement, 15 | output [15:0] source_out, 16 | output [15:0] destination_out, 17 | output reg [15:0] flags_out 18 | ); 19 | 20 | reg [15:0] r1; 21 | reg [15:0] r2; 22 | reg [15:0] r3; 23 | 24 | reg [15:0] reg_current_value; 25 | always @* begin 26 | case(source_select[1:0]) 27 | 3'h0: reg_current_value = source_select[2] ? (flags_value & {16{source_immediate}}) : pc; 28 | 3'h1: reg_current_value = r1; 29 | 3'h2: reg_current_value = r2; 30 | 3'h3: reg_current_value = r3; 31 | endcase 32 | end 33 | 34 | reg [15:0] dest_base_value; 35 | always @* begin 36 | case(destination_select[1:0]) 37 | 3'h0: dest_base_value = destination_select[2] ? flags_value : pc; 38 | 3'h1: dest_base_value = r1; 39 | 3'h2: dest_base_value = r2; 40 | 3'h3: dest_base_value = r3; 41 | endcase 42 | end 43 | 44 | wire [15:0] full_immediate = {{9{immediate[6]}}, immediate}; 45 | assign source_out = reg_current_value + full_immediate; 46 | 47 | wire [15:0] pre_increment_value = {{15{decrement & pre_increment}}, pre_increment}; 48 | assign destination_out = dest_base_value + pre_increment_value; 49 | 50 | wire [15:0] post_increment_value = {{15{decrement & post_increment}}, post_increment}; 51 | wire [15:0] reg_incremented = source_out + post_increment_value; 52 | wire should_store_reg = post_increment; 53 | 54 | wire store_register = (store_value & destination_select[2]); 55 | wire [15:0] dest_incremented = store_register ? destination_write : destination_out + post_increment_value; 56 | wire should_store_dest = post_increment | store_register; 57 | 58 | wire [15:0] r1_result = (should_store_dest & destination_select == 2'h1) ? dest_incremented : 59 | (should_store_reg & source_select == 2'h1) ? source_incremented : r1; 60 | 61 | wire [15:0] r2_result = (should_store_dest & destination_select == 2'h2) ? dest_incremented : 62 | (should_store_reg & source_select == 2'h2) ? source_incremented : r2; 63 | 64 | wire [15:0] r3_result = (should_store_dest & destination_select == 2'h3) ? dest_incremented : 65 | (should_store_reg & source_select == 2'h3) ? source_incremented : r3; 66 | 67 | wire [15:0] flags_result = set_flags ? flags_value : 68 | (store_value & destination_select == 3'h4) ? destination_write : flags_out; 69 | 70 | always @(posedge clock) 71 | begin 72 | r1 <= r1_result; 73 | r2 <= r2_result; 74 | r3 <= r3_result; 75 | flags_out <= flags_result; 76 | end 77 | 78 | endmodule 79 | -------------------------------------------------------------------------------- /hardware/grok80/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile borrowed from https://github.com/cliffordwolf/icestorm/blob/master/examples/icestick/Makefile 2 | # 3 | # The following license is from the icestorm project and specifically applies to this file only: 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | PROJ = top 18 | VERILOG = top.v \ 19 | src/memory_block.v 20 | #VERILOG = top.v \ 21 | # src/cpu.v \ 22 | # src/dff.v \ 23 | # src/memory_block.v \ 24 | # src/alu.v \ 25 | # src/effect_decoder.v \ 26 | # src/devices.v \ 27 | # src/parallel_buffer.v \ 28 | # src/uart_device.v\ 29 | # src/uart_tx.v \ 30 | # src/uart_rx.v 31 | 32 | PIN_DEF = pins.pcf 33 | DEVICE = lp8k 34 | 35 | all: $(PROJ).rpt $(PROJ).bin 36 | 37 | %.blif: %.v 38 | yosys -p 'synth_ice40 -blif $@' $(VERILOG) 39 | 40 | %.asc: $(PIN_DEF) %.blif 41 | arachne-pnr -d 8k -P cm81 -o $@ -p $^ 42 | 43 | %.bin: %.asc 44 | icepack $< $@ 45 | 46 | %.rpt: %.asc 47 | icetime -d $(DEVICE) -mtr $@ $< 48 | 49 | %_tb: %_tb.v %.v 50 | iverilog -o $@ $^ 51 | 52 | %_tb.vcd: %_tb 53 | vvp -N $< +vcd=$@ 54 | 55 | %_syn.v: %.blif 56 | yosys -p 'read_blif -wideports $^; write_verilog $@' 57 | 58 | %_syntb: %_tb.v %_syn.v 59 | iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` 60 | 61 | %_syntb.vcd: %_syntb 62 | vvp -N $< +vcd=$@ 63 | 64 | prog: $(PROJ).bin 65 | tinyprog -p $< 66 | 67 | sudo-prog: $(PROJ).bin 68 | @echo 'Executing prog as root!!!' 69 | sudo tinyprog -p $< 70 | 71 | clean: 72 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin 73 | 74 | .SECONDARY: 75 | .PHONY: all prog clean 76 | -------------------------------------------------------------------------------- /hardware/grok80/prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 41c0 0000 41c0 0000 41c0 0000 41c0 0000 41c0 0000 01c0 000c 41c0 0020 2 | 41c0 0000 41c0 0fff 41c0 0400 0040 0088 4140 0400 414a 4003 414a 3001 417b 401f 3 | 0020 0004 414b 401f 1140 2003 414c 2020 114a 2004 1640 0002 464a 0400 427b 0023 4 | 0010 0006 4240 0058 414a 1001 427b 0000 0000 000a 427b 002e 0010 0004 4240 004f 5 | 0040 ffda 01c0 0008 41c0 0020 41c0 0400 0040 00ac 01c0 0008 41c0 0020 41c0 000d 6 | 0040 0082 01c0 0008 41c0 0020 41c0 000d 0040 007a 01c0 0008 41c0 0020 11c0 0003 7 | 0040 00ca 0040 0000 f1c0 0000 1f40 0004 1640 0001 1172 2002 0000 0024 01c0 0004 8 | 0040 0024 1172 3003 0000 000a 01c0 0008 11c0 0005 21c0 0000 0040 0056 427b 000a 9 | 4200 0000 0000 000e 427b 000d 4200 0000 0000 0008 6640 0001 414b 2001 0010 ffe0 10 | 1f40 0000 10c0 0005 4b71 1200 0000 fffe b240 0004 4b40 4000 10c0 0000 f1c0 0000 11 | 1f40 0004 1640 0001 1172 2002 0000 001e 01c0 0004 0040 001e 1172 3003 0000 000a 12 | 01c0 0008 11c0 0005 21c0 0000 0040 001c 427b 0003 4200 0000 0000 0008 6640 0001 13 | 414b 2001 0010 ffe6 1f40 0000 10c0 0005 4b71 1200 0000 fffe b240 0004 4b40 4000 14 | 10c0 0000 f1c0 0000 1f40 0002 4b71 1100 0000 fffe 1b40 3001 1f40 0000 10c0 0003 15 | 01c0 0008 11c0 0002 11c0 0002 0040 000e 01c0 0008 11c0 0002 01c0 0006 0040 0006 16 | 10c0 0002 000d 0000 f1c0 0000 1f40 0002 1640 0001 2272 0000 0000 000c 4b71 1100 17 | 0000 fffe 2b40 3000 464a 0001 0040 fff4 1f40 0000 10c0 0003 1640 0000 41c0 0000 18 | 4140 4000 2140 0000 4172 0000 0000 0012 414b 0030 0020 000e 417b 000a 0030 000a 19 | 414c 400a 114a 4000 6640 0001 0040 ffec 10c0 0003 5540 ffff 01c0 0006 11c0 0002 20 | 0040 004e 11c0 0000 4146 000c 0000 000c 4141 000f 01c0 0008 11c0 0004 11c0 0002 21 | 0040 0030 1140 0001 4146 0008 0000 000c 4141 000f 01c0 0008 11c0 0004 11c0 0002 22 | 0040 0020 1140 0001 4146 0004 0000 000c 4141 000f 01c0 0008 11c0 0004 11c0 0002 23 | 0040 0010 1140 0001 4141 000f 01c0 0008 11c0 0004 11c0 0002 0040 0004 10c0 0004 24 | 41c0 0030 114a 0001 01c0 0008 11c0 0003 11c0 0002 0040 ff58 10c0 0003 4140 2000 25 | 414b 03e8 0020 0006 414a 2001 0040 fffa 4145 200c 414a 03e8 414b 0064 0020 0006 26 | 414a 2100 0040 fffa 414a 0064 414b 000a 0020 0006 414a 2010 0040 fffa 414a 000a 27 | 114a 2000 10c0 0001 -------------------------------------------------------------------------------- /hardware/grok80/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | iverilog -o test_bench \ 5 | test/defines.v \ 6 | src/dff.v test/dff_tb.v 7 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 8 | echo "Found $FAILURES failures in dff_tb.v." 9 | 10 | iverilog -o test_bench \ 11 | test/defines.v \ 12 | src/memory_block.v test/memory_block_tb.v 13 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 14 | echo "Found $FAILURES failures in memory_block_tb.v." 15 | 16 | iverilog -o test_bench \ 17 | test/defines.v \ 18 | src/alu.v test/alu_tb.v 19 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 20 | echo "Found $FAILURES failures in alu_tb.v." 21 | 22 | iverilog -o test_bench \ 23 | test/defines.v \ 24 | src/effect_decoder.v test/effect_decoder_tb.v 25 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 26 | echo "Found $FAILURES failures in effect_decoder_tb.v." 27 | 28 | iverilog -o test_bench \ 29 | test/defines.v \ 30 | src/uart_tx.v test/uart_tx_tb.v 31 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 32 | echo "Found $FAILURES failures in uart_tx_tb.v." 33 | 34 | iverilog -o test_bench \ 35 | test/defines.v \ 36 | src/alu.v \ 37 | src/dff.v \ 38 | src/effect_decoder.v \ 39 | src/memory_block.v \ 40 | src/parallel_buffer.v \ 41 | src/uart_tx.v \ 42 | src/uart_rx.v \ 43 | src/uart_device.v \ 44 | src/devices.v \ 45 | src/cpu.v test/cpu_tb.v 46 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 47 | echo "Found $FAILURES failures in cpu_tb.v." 48 | 49 | #iverilog -o test_bench \ 50 | # test/defines.v \ 51 | # src/parallel_buffer.v \ 52 | # src/uart_tx.v \ 53 | # src/uart_device.v test/uart_device_tb.v 54 | #FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 55 | #echo "Found $FAILURES failures in uart_device_tb.v." 56 | 57 | iverilog -o test_bench \ 58 | test/defines.v \ 59 | src/uart_rx.v test/uart_rx_tb.v 60 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 61 | echo "Found $FAILURES failures in uart_rx_tb.v." 62 | -------------------------------------------------------------------------------- /hardware/grok80/src/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input [15:0] source, 3 | input [15:0] destination, 4 | input [3:0] op_code, 5 | input [15:0] flags, 6 | output [15:0] result_out, 7 | output [15:0] flags_out, 8 | output write_flags 9 | ); 10 | 11 | parameter DIVISION = 0; 12 | 13 | wire [31:0] mult_result = source * destination; 14 | 15 | wire [31:0] signed_shift_destination = { {16{flags[8] & destination[15]}}, destination }; 16 | assign result_out = result[15:0]; 17 | wire carry = result[16]; 18 | wire [16:0] result = 19 | //Bit operations 20 | op_code == 4'h0 ? source : // Copy 21 | op_code == 4'h1 ? source & destination : // AND 22 | op_code == 4'h2 ? source | destination : // OR 23 | op_code == 4'h3 ? source ^ destination : // XOR 24 | op_code == 4'h4 ? ~source : // inverse 25 | 26 | //Shift operations 27 | op_code == 4'h5 ? destination << source : // Shift left 28 | // shift signed/unsigned by sign flag 29 | op_code == 4'h6 ? source > 16'hF ? {16{flags[8] & destination[15]}} : signed_shift_destination >> source[3:0] : 30 | op_code == 4'h7 ? { source[7:0], source[15:8] } : // Swap 31 | op_code == 4'h8 ? { source[15:8], 8'h00 } : // High byte 32 | op_code == 4'h9 ? { 8'h00, source[7:0] } : // Low byte 33 | 34 | op_code == 4'hA ? destination + source : // Add 35 | op_code == 4'hB ? destination - source : // Subtract 36 | op_code == 4'hC ? mult_result[15:0] : // Multiply 37 | op_code == 4'hD ? mult_result[31:16] : // Multiply upper word 38 | op_code == 4'hE ? destination + source + flags[2] : // Add with carry 39 | 0; // TBD 40 | 41 | wire zero = result[15:0] == 15'h0; 42 | wire negative = result[15]; 43 | wire overflow = carry; 44 | wire divide_error = op_code == 4'hD && source == 16'h0; 45 | 46 | assign flags_out = { flags[15:5], divide_error, overflow, carry, negative, zero }; 47 | assign write_flags = op_code != 4'h0; 48 | endmodule 49 | -------------------------------------------------------------------------------- /hardware/grok80/src/devices.v: -------------------------------------------------------------------------------- 1 | module devices ( 2 | input clock, 3 | input write_enable, 4 | input [15:0] address, 5 | input [15:0] data_in, 6 | input rx, 7 | output reg [15:0] data_out, 8 | output tx, 9 | output [15:0] peek 10 | ); 11 | 12 | wire control = address[15:12] == 4'h0; 13 | wire [7:0] target_device = control ? address[11:4] : address[15:8]; 14 | 15 | always @(posedge clock) begin 16 | data_out <= 17 | target_device == 8'h2 ? uart_data_out : 18 | 16'h0; 19 | end 20 | 21 | wire [15:0] uart_data_out; 22 | uart_device #(.DEVICE_ID(16'h100)) uart_device( 23 | .clock(clock), 24 | .write_enable(write_enable & target_device == 8'h2), 25 | .control(control), 26 | .address(address[7:0]), 27 | .data_in(data_in), 28 | .rx(rx), 29 | .data_out(uart_data_out), 30 | .tx(tx), 31 | .peek(peek) 32 | ); 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /hardware/grok80/src/dff.v: -------------------------------------------------------------------------------- 1 | module dff( 2 | input clock, 3 | input [WIDTH-1:0] d, 4 | input async_reset, 5 | input enable, 6 | output reg [WIDTH-1:0] q 7 | ); 8 | parameter WIDTH = 1; 9 | parameter INIT = {WIDTH{1'b0}}; 10 | 11 | initial q = INIT; 12 | 13 | always @ (posedge clock or posedge async_reset) 14 | if (async_reset) begin 15 | q <= INIT; 16 | end else if (enable == 1) begin 17 | q <= d; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/src/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder ( 2 | input [15:0] flags, 3 | input [2:0] effect, 4 | output store 5 | ); 6 | assign store = 7 | effect == 3'h0 ? flags[0] : 8 | effect == 3'h1 ? ~flags[0] : 9 | effect == 3'h2 ? flags[1] : 10 | effect == 3'h3 ? ~flags[1] & ~flags[0] : 11 | effect == 3'h4 ? 1 : 12 | effect == 3'h5 ? flags[3] : 13 | effect == 3'h6 ? flags[4] : 14 | 0; 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/grok80/src/memory_block.v: -------------------------------------------------------------------------------- 1 | module memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [15:0] read_address, 5 | input [15:0] write_address, 6 | input [15:0] data_in, 7 | output [15:0] data_out, 8 | output reg [31:0] read_data 9 | ); 10 | 11 | parameter WORDS = 65536; 12 | parameter ADDRESS_WIDTH = 16; 13 | parameter MEM_INIT_FILE = "prog.hex"; 14 | 15 | reg [31:0] mem[(WORDS-1)/2:0]; 16 | 17 | initial begin 18 | if (MEM_INIT_FILE != "") begin 19 | $readmemh(MEM_INIT_FILE, mem); 20 | end 21 | end 22 | 23 | assign data_out = read_address[0] ? read_data[31:16] : read_data[15:0]; 24 | 25 | assign data_out = read_address[0] ? read_data[31:16] : read_data[15:0]; 26 | 27 | always @(negedge clock) begin 28 | read_data <= mem[read_address]; 29 | 30 | if(write_enable) 31 | if (write_address[0]) 32 | mem[write_address][31:16] <= data_in; 33 | else 34 | mem[write_address][15:0] <= data_in; 35 | end 36 | 37 | endmodule 38 | -------------------------------------------------------------------------------- /hardware/grok80/src/parallel_buffer.v: -------------------------------------------------------------------------------- 1 | module parallel_buffer( 2 | input clock, 3 | input [WIDTH-1:0] data_in, 4 | input write_in, 5 | input next_ready, 6 | output write_ready, 7 | output reg [WIDTH-1:0] data_out, 8 | output reg write_out 9 | ); 10 | parameter WIDTH = 8; 11 | initial write_out = 0; 12 | 13 | assign write_ready = ~write_out | next_ready; 14 | 15 | always @(posedge clock) begin 16 | if (write_ready & write_in) begin 17 | data_out <= data_in; 18 | write_out <= 1'b1; 19 | end else if (write_out & next_ready) begin 20 | data_out <= 0; 21 | write_out <= 1'b0; 22 | end 23 | end 24 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/src/register_block.v: -------------------------------------------------------------------------------- 1 | module register_block ( 2 | input clock, 3 | input reset, 4 | 5 | // Read arguments 6 | input [3:0] source, 7 | input [15:0] immediate, 8 | input [3:0] dest, 9 | input [15:0] offset, 10 | 11 | // Write arguments 12 | input [3:0] to_write, 13 | input write_enable, 14 | input push, 15 | input pop, 16 | input [15:0] data_in, 17 | 18 | // Read out 19 | output [15:0] source_out, 20 | output [15:0] dest_out, 21 | 22 | // Control registers in 23 | input [15:0] flags_in, 24 | input write_flags, 25 | 26 | // Control registers out 27 | output [15:0] pc, 28 | output [15:0] banking, 29 | output [15:0] flags, 30 | output [15:0] interrupt 31 | ); 32 | 33 | wire [15:0][10] registers_out; 34 | 35 | assign pc = registers_out[0]; 36 | assign banking = registers_out[4]; 37 | assign flags = registers_out[8]; 38 | assign interrupt = registers_out[9]; 39 | 40 | wire [15:0] inc_amt = 41 | push ? 16'hFFFF : 42 | pop ? 16'h0001 : 43 | 16'h0000; 44 | 45 | wire [15:0] write_value = write_enable ? data_in : to_write_out + inc_amt; 46 | wire [15:0][10] d_in = { 47 | to_write == 4'h0 && write_enable ? data_in : pc + 2, 48 | write_value, 49 | write_value, 50 | write_value, 51 | write_value, 52 | write_value, 53 | write_value, 54 | write_value, 55 | to_write == 4'h8 && write_enable ? data_in : flags_in, 56 | write_value 57 | } 58 | 59 | 60 | dff #(.WIDTH(16), .INIT(16'h0)) registers[10] ( 61 | .clock(clock), 62 | .d(d_in), 63 | .async_reset(reset), 64 | .enable((inc_r1 | store_r1) && step == 2'h0), 65 | .q(registers_out) 66 | ); 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /hardware/grok80/src/uart_device.v: -------------------------------------------------------------------------------- 1 | module uart_device( 2 | input clock, 3 | input write_enable, 4 | input control, 5 | input [7:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | assign peek = control_read; 14 | 15 | parameter DEVICE_ID = 16'h0; 16 | parameter DEVICE_TYPE = 8'h4; 17 | 18 | wire control_write = control & write_enable; 19 | wire [3:0] control_address = address[3:0]; 20 | wire [7:0] rx_data_out; 21 | wire rx_data_ready; 22 | 23 | wire [15:0] control_read = 24 | control_address == 4'h0 ? DEVICE_ID : 25 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 26 | control_address == 4'h2 ? baud_clock_divider : 27 | control_address == 4'h4 ? { 8'h0, rx_data_out } : 28 | 16'h0; 29 | 30 | assign data_out = control ? control_read : 16'h0; 31 | 32 | wire in_progress = ~write_ready | ~ready_p1p2 | ~tx_ready; 33 | wire [7:0] flags = { 4'h1, 1'b0, in_progress, rx_data_ready, write_ready }; 34 | 35 | reg [15:0] baud_clock_divider; 36 | initial baud_clock_divider = 16'h8B; // 115200 baud 37 | 38 | wire buffer_write_en = control_write & control_address == 4'h3; 39 | 40 | always @(posedge clock) begin 41 | if (control_write & control_address == 4'h2) 42 | baud_clock_divider <= data_in; 43 | end 44 | 45 | wire write_p1p2; 46 | wire ready_p1p2; 47 | wire [7:0] data_p1p2; 48 | wire tx_ready; 49 | wire [7:0] tx_data; 50 | wire tx_write; 51 | 52 | wire write_ready; 53 | parallel_buffer #(.WIDTH(8)) pb1( 54 | .clock(clock), 55 | .data_in(data_in[7:0]), 56 | .write_in(buffer_write_en), 57 | .next_ready(ready_p1p2), 58 | .write_ready(write_ready), 59 | .data_out(data_p1p2), 60 | .write_out(write_p1p2) 61 | ); 62 | 63 | parallel_buffer #(.WIDTH(8)) pb2( 64 | .clock(clock), 65 | .data_in(data_p1p2), 66 | .write_in(write_p1p2), 67 | .next_ready(tx_ready), 68 | .write_ready(ready_p1p2), 69 | .data_out(tx_data), 70 | .write_out(tx_write) 71 | ); 72 | 73 | uart_tx uart_tx( 74 | .clock(clock), 75 | .clock_divider(baud_clock_divider), 76 | .data_in(tx_data), 77 | .write_en(tx_write), 78 | .data_ready(tx_ready), 79 | .tx(tx) 80 | ); 81 | 82 | wire [15:0] rx_buffer_out; 83 | 84 | uart_rx uart_rx( 85 | .clock(clock), 86 | .clock_divider(baud_clock_divider), 87 | .read_en(control_address == 4'h4 & control_write), 88 | .rx(rx), 89 | .data_ready(rx_data_ready), 90 | .data_out(rx_data_out) 91 | ); 92 | endmodule 93 | -------------------------------------------------------------------------------- /hardware/grok80/src/uart_rx.v: -------------------------------------------------------------------------------- 1 | module uart_rx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input read_en, 5 | input rx, 6 | output reg data_ready, 7 | output reg [WIDTH-1:0] data_out 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | initial data_ready = 0; 12 | 13 | reg reading = 0; // Are we currently reading a byte? 14 | reg [15:0] clock_counter = 0; // Counts up to the clock divider 15 | reg [3:0] bit_number; // Which bit are we currently reading? 16 | reg [7:0] buffer = 8'h0; // Shift buffer for incoming bits 17 | reg buffer_ready = 0; // 1 if buffer has a valid byte value for read 18 | 19 | always @(posedge clock) begin 20 | if (~reading) begin 21 | // Bit number stays at zero while waiting for the next byte 22 | bit_number <= 4'h0; 23 | if (~rx) begin 24 | // RX went low, count to half the baud clock width and sample 25 | clock_counter <= clock_divider[15:1] + 1'b1; 26 | reading <= 1'b1; 27 | end 28 | end else begin 29 | if (clock_counter == clock_divider) begin 30 | // take a sample 31 | if (bit_number == 4'h0) begin 32 | // We are still in the start bit, init details 33 | buffer_ready <= 1'b0; // About to write to this 34 | bit_number <= bit_number + 1; 35 | // Clock counter starts at 1 indexed so you can calc 36 | // the divider value based without accounting for zero bit 37 | clock_counter <= 16'h1; 38 | end else if (bit_number == 4'h9) begin 39 | // Stop bit, if rx is low, we took too long, read right away 40 | reading = ~rx; 41 | if (~rx) begin 42 | // We took too long on the last byte, this time 43 | // Remove one clock cycle and go straight into the 44 | // next start bit 45 | clock_counter <= clock_divider[15:2]; 46 | bit_number <= 4'h0; 47 | end 48 | end else begin 49 | if (bit_number == 4'h8) begin 50 | // We read all 8 bits, byte is ready to move into 51 | // the output value 52 | buffer_ready <= 1'b1; 53 | end 54 | clock_counter <= 16'h1; 55 | bit_number <= bit_number + 1; 56 | buffer = { rx, buffer[7:1] }; 57 | end 58 | end else begin 59 | clock_counter <= clock_counter + 1; 60 | end 61 | end 62 | end 63 | 64 | // make sure buffer ready goes low at least once between reads 65 | // to ensure we don't read the same value twice 66 | reg new_data = 0; 67 | always @(posedge clock) begin 68 | if (~data_ready & buffer_ready & new_data) begin 69 | data_out <= buffer; 70 | data_ready <= 1'b1; 71 | new_data <= 1'b0; 72 | end else if (read_en) begin 73 | data_ready <= 1'b0; 74 | end else if (~buffer_ready) begin 75 | new_data <= 1'b1; 76 | end 77 | end 78 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/src/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input [WIDTH-1:0] data_in, 5 | input write_en, 6 | output data_ready, 7 | output tx 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | reg [15:0] clock_count; 12 | initial clock_count = 0; 13 | 14 | reg [WIDTH+1:0] data; 15 | reg [3:0] shift_remaining; 16 | initial shift_remaining = 0; 17 | assign tx = data_ready | data[0]; 18 | assign data_ready = shift_remaining == 0; 19 | 20 | always @(posedge clock) begin 21 | if (data_ready & write_en) begin 22 | data <= { 1'b1, data_in, 1'b0 }; 23 | shift_remaining = WIDTH + 2; 24 | clock_count <= 0; 25 | end else if (~data_ready) begin 26 | if (clock_count == clock_divider) begin 27 | shift_remaining = shift_remaining - 1; 28 | data <= { 1'b1, data[WIDTH:1] }; 29 | clock_count <= 0; 30 | end else begin 31 | clock_count = clock_count + 1; 32 | end 33 | end 34 | end 35 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/test/defines.v: -------------------------------------------------------------------------------- 1 | `define assert(signal, value) if (signal !== value) begin $display("ASSERTION FAILED in %m: signal != value"); $finish; end 2 | -------------------------------------------------------------------------------- /hardware/grok80/test/dff_tb.v: -------------------------------------------------------------------------------- 1 | module dff_tb; 2 | 3 | // Setup registers for the DFF inputs 4 | reg clock; 5 | reg [15:0] d; 6 | reg a_reset; 7 | reg enable; 8 | 9 | // Setup a wire for the dff output "q" 10 | wire [15:0] q; 11 | 12 | // Instantiate the unit under test 13 | dff #(.WIDTH(16)) dff( 14 | .clock(clock), 15 | .d(d), 16 | .async_reset(a_reset), 17 | .enable(enable), 18 | .q(q) 19 | ); 20 | 21 | initial begin 22 | // Initialize standard setup 23 | clock = 0; 24 | d = 16'h0; 25 | a_reset = 0; 26 | enable = 1; 27 | 28 | #20 d = 16'hFFFF; 29 | // Should capture on positive clock edge 30 | #20 clock = 1; 31 | #1 `assert(q, 16'hFFFF); 32 | 33 | // Should not capture without positive clock edge 34 | #20 d = 16'h1111; 35 | #1 `assert(q, 16'hFFFF); 36 | #20 clock = 0; 37 | #1 `assert(q, 16'hFFFF); 38 | 39 | // Reset sets output and holds output at 0 40 | #20 a_reset = 1; 41 | #1 `assert(q, 16'h0000); 42 | #20 clock = 1; 43 | #1 `assert(q, 16'h0000); 44 | #20 a_reset = 0; 45 | #1 `assert(q, 16'h0000); 46 | 47 | // Enable held at 0 makes DFF unresponsive to clock 48 | #20 d = 16'hF42F; 49 | #1 `assert(q, 16'h0000); 50 | enable = 0; 51 | #1 `assert(q, 16'h0000); 52 | #20 clock = 0; 53 | #1 `assert(q, 16'h0000); 54 | #20 clock = 1; 55 | #1 `assert(q, 16'h0000); 56 | 57 | // Enable assertion doesn't capture input 58 | #20 enable = 1; 59 | #1 `assert(q, 16'h0000); 60 | #20 clock = 0; 61 | #1 `assert(q, 16'h0000); 62 | // Positive edge captures input 63 | #20 clock = 1; 64 | #1 `assert(q, 16'hF42F); 65 | end 66 | 67 | initial begin 68 | $monitor("clock=%d, d=%04x, async_reset=%d, enable=%d, q=%04x", clock, d, a_reset, enable, q); 69 | end 70 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/test/effect_decoder_tb.v: -------------------------------------------------------------------------------- 1 | module effect_decoder_tb; 2 | 3 | // Setup registers for the inputs 4 | reg [15:0] flags; 5 | reg [2:0] effect; 6 | 7 | // Setup a wire for the outputs 8 | wire store; 9 | 10 | // Instantiate the unit under test 11 | effect_decoder effect_decoder( 12 | .flags(flags), 13 | .effect(effect), 14 | .store(store) 15 | ); 16 | 17 | initial begin 18 | // Initialize standard setup 19 | flags = 16'h0; 20 | effect = 3'h0; 21 | 22 | #1 `assert(store, 0); 23 | // TODO Implement these tests 24 | end 25 | 26 | initial begin 27 | $monitor("flags=%04x, effect=%d, store=%x", flags, effect, store); 28 | end 29 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/test/memory_block_tb.v: -------------------------------------------------------------------------------- 1 | module memory_block_tb; 2 | 3 | // Setup registers for the inputs 4 | reg clock; 5 | reg write_enable; 6 | reg [15:0] read_address; 7 | reg [15:0] write_address; 8 | reg [15:0] data_in; 9 | 10 | // Setup a wire for the output 11 | wire [15:0] data_out; 12 | 13 | // Instantiate the unit under test 14 | memory_block #(.WIDTH(14), .MEM_INIT_FILE("test/test_prog.hex")) memory_block( 15 | .clock(clock), 16 | .write_enable(write_enable), 17 | .read_address(read_address), 18 | .write_address(write_address), 19 | .data_in(data_in), 20 | .data_out(data_out) 21 | ); 22 | 23 | initial begin 24 | // Initialize standard setup 25 | clock = 0; 26 | write_enable = 0; 27 | read_address = 16'h0; 28 | write_address = 16'h0; 29 | data_in = 16'h0; 30 | 31 | // Read initial data from file 32 | #20 clock = 1; 33 | #1 `assert(data_out, 16'h4540); 34 | #20 clock = 0; 35 | 36 | // Set output to 0, a known value 37 | #20 write_enable = 1; 38 | #20 clock = 1; 39 | // data written 40 | #20 clock = 0; 41 | #20 clock = 1; 42 | // data read 43 | #1 `assert(data_out, 16'h0000); 44 | 45 | #20 clock = 0; 46 | #20 clock = 1; 47 | #1 write_enable = 0; 48 | #1 data_in = 16'hAAAA; 49 | #20 clock = 0; 50 | #20 clock = 1; 51 | #1 `assert(data_out, 16'h0000); 52 | 53 | // Memory is pseudo dual port, doesn't immediately write through 54 | #1 data_in = 16'hAAAA; 55 | #1 write_enable = 1; 56 | #20 clock = 0; 57 | #20 clock = 1; 58 | #1 `assert(data_out, 16'h0000); 59 | #1 write_enable = 0; 60 | #20 clock = 0; 61 | // Doesn't read on negative edge 62 | #1 `assert(data_out, 16'h0000); 63 | #20 clock = 1; 64 | // Only reads on positive edge 65 | #1 `assert(data_out, 16'hAAAA); 66 | end 67 | 68 | initial begin 69 | $monitor( 70 | "clock=%04x, write_enable=%d, read_address=%04x, write_address=%04x, data_in=%04x, data_out=%04x", 71 | clock, write_enable, read_address, write_address, data_in, data_out); 72 | end 73 | endmodule -------------------------------------------------------------------------------- /hardware/grok80/test/test_prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 41c0 07ff 1540 0000 4540 0000 4640 ffff 61c0 0000 1540 0000 4540 0000 2 | 41c0 0400 17c0 0000 51c0 0000 1540 0000 4540 0000 41c0 0400 41c0 000a 5640 0001 3 | 12c0 1000 1540 0000 0040 0000 -------------------------------------------------------------------------------- /hardware/grok80/test/test_prog.ucisc: -------------------------------------------------------------------------------- 1 | # Specialized version of https://github.com/grokthis/ucisc-kotlin/tree/trunk/src/ucisc/test 2 | # designed to avoid halts and let the verilog simulator step through and verify state 3 | 4 | ##################### 5 | # Stack Setup Tests # 6 | ##################### 7 | 8 | testMaxImm: 9 | copy val 0 &stack 10 | copy val 2047 stack 0 push 11 | # expect r1 = FFFF 12 | copy r1 0 &r1 13 | # expect r1 = 2047 14 | 15 | # Begin instruction 4 16 | testMaxImmReg: 17 | copy val 0 &stack 18 | copy val 65535 &r2 19 | copy &r2 0 stack 0 push 20 | # expect r1 = FFFF 21 | copy r1 0 &r1 22 | # expect r1 = FFFF 23 | 24 | # Begin instruction 8 25 | testPopStack: 26 | copy val 0 &stack 27 | copy val 1024 stack 0 push 28 | # expect r1 = FFFF 29 | copy stack 0 &r3 pop 30 | # expect r1 = 0000 31 | copy &stack 0 stack 0 push 32 | # expect r1 = FFFF 33 | copy stack 0 &stack 34 | # expect r1 = 0000 35 | 36 | # Begin instruction 13 37 | testMemCopy1: 38 | copy val 0 &stack 39 | copy val 1024 stack 0 push 40 | # expect r1 = FFFF 41 | copy val 10 stack 0 push 42 | # expect r1 = FFFE 43 | copy &stack 1 &r2 44 | copy stack 0 r2 1 push 45 | # expect r1 = FFFE 46 | copy stack 0 &stack 47 | # expect r1 = 000A 48 | copy pc 0 pc -------------------------------------------------------------------------------- /hardware/grok80/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input CLK, 3 | input write_enable, 4 | input [15:0] readA_address, 5 | output reg [15:0] dataA_out, 6 | input [15:0] readB_address, 7 | output reg [15:0] dataB_out, 8 | input [16:0] readC_address, 9 | output reg [15:0] dataC_out, 10 | input [16:0] write_address, 11 | input [15:0] data_in 12 | ); 13 | 14 | memory_block memory_block1( 15 | .clock(CLK), 16 | .write_enable(write_enable), 17 | .read_address(readA_address), 18 | .data_out(dataA_out), 19 | .write_address(write_address), 20 | .data_in(data_in) 21 | ); 22 | 23 | memory_block memory_block2( 24 | .clock(CLK), 25 | .write_enable(write_enable), 26 | .read_address(readB_address), 27 | .data_out(dataB_out), 28 | .write_address(write_address), 29 | .data_in(data_in) 30 | ); 31 | 32 | memory_block #(.WORDS(81920), .ADDRESS_WIDTH(17)) memory_block3 33 | ( 34 | .clock(CLK), 35 | .write_enable(write_enable), 36 | .read_address(readC_address), 37 | .data_out(dataC_out), 38 | .write_address(write_address), 39 | .data_in(data_in) 40 | ); 41 | 42 | //module top( 43 | // input CLK, 44 | // input PIN_2, 45 | // input PIN_3, 46 | // output LED, 47 | // output PIN_24, 48 | // output PIN_23, 49 | // output PIN_22, 50 | // output PIN_21, 51 | // output PIN_20, 52 | // output PIN_19, 53 | // output PIN_18, 54 | // output PIN_17, 55 | // output PIN_16, 56 | // output PIN_15, 57 | // output PIN_14, 58 | // output PIN_13, 59 | // output PIN_12, 60 | // output PIN_11, 61 | // output PIN_10, 62 | // output PIN_9, 63 | // output PIN_8, 64 | // output PIN_7, 65 | // output PIN_6, 66 | // output PIN_5, 67 | // output PIN_4, 68 | // output PIN_1 69 | //); 70 | // 71 | //parameter address_width = 13; 72 | // 73 | //assign PIN_24 = r1[15]; 74 | //assign PIN_23 = r1[14]; 75 | //assign PIN_22 = r1[13]; 76 | //assign PIN_21 = r1[12]; 77 | //assign PIN_20 = r1[11]; 78 | //assign PIN_19 = r1[10]; 79 | //assign PIN_18 = r1[9]; 80 | //assign PIN_17 = r1[8]; 81 | // 82 | //assign PIN_16 = r1[7]; 83 | //assign PIN_15 = r1[6]; 84 | //assign PIN_14 = r1[5]; 85 | //assign PIN_9 = r1[4]; 86 | //assign PIN_10 = r1[3]; 87 | //assign PIN_11 = r1[2]; 88 | //assign PIN_12 = r1[1]; 89 | //assign PIN_13 = r1[0]; 90 | // 91 | //assign PIN_4 = pc[5]; 92 | //assign PIN_5 = pc[4]; 93 | //assign PIN_6 = pc[3]; 94 | //assign PIN_7 = pc[2]; 95 | //assign PIN_8 = pc[1]; 96 | //assign PIN_1 = tx; 97 | //wire rx = PIN_3; 98 | // 99 | //reg [24:0] slow_clock; 100 | //initial slow_clock = 25'h0; 101 | // 102 | //always @(posedge CLK) begin // & PIN_1 103 | // slow_clock <= slow_clock + 1; 104 | //end 105 | // 106 | //wire clock = CLK; 107 | // 108 | ////reg clock; 109 | ////initial clock = 0; 110 | ////always @* begin 111 | //// // Debounce clock buttons 112 | //// clock <= PIN_1 | ((~PIN_2) & clock); 113 | ////end 114 | ////assign LED = store_reg; 115 | // 116 | //wire [1:0] step; 117 | //wire [15:0] r1; 118 | //wire [15:0] pc; 119 | //wire tx; 120 | ////assign LED = tx; 121 | // 122 | //cpu cpu( 123 | // .clock_input(clock), 124 | // .reset(PIN_2), 125 | // .step(step), 126 | // .r1_peek(r1), 127 | // .pc_peek(pc), 128 | // .tx(tx), 129 | // .rx(rx) 130 | //); 131 | 132 | endmodule 133 | -------------------------------------------------------------------------------- /hardware/reference/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile borrowed from https://github.com/cliffordwolf/icestorm/blob/master/examples/icestick/Makefile 2 | # 3 | # The following license is from the icestorm project and specifically applies to this file only: 4 | # 5 | # Permission to use, copy, modify, and/or distribute this software for any 6 | # purpose with or without fee is hereby granted, provided that the above 7 | # copyright notice and this permission notice appear in all copies. 8 | # 9 | # THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | # WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | # MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | # ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | # WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | # ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | # OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | 17 | PROJ = top 18 | VERILOG = top.v \ 19 | src/cpu.v \ 20 | src/dff.v \ 21 | src/memory_block.v \ 22 | src/alu.v \ 23 | src/effect_decoder.v \ 24 | src/devices.v \ 25 | src/parallel_buffer.v \ 26 | src/uart_device.v\ 27 | src/uart_tx.v \ 28 | src/uart_rx.v 29 | 30 | PIN_DEF = pins.pcf 31 | DEVICE = lp8k 32 | 33 | all: $(PROJ).rpt $(PROJ).bin 34 | 35 | %.blif: %.v 36 | yosys -p 'synth_ice40 -blif $@' $(VERILOG) 37 | 38 | %.asc: $(PIN_DEF) %.blif 39 | arachne-pnr -d 8k -P cm81 -o $@ -p $^ 40 | 41 | %.bin: %.asc 42 | icepack $< $@ 43 | 44 | %.rpt: %.asc 45 | icetime -d $(DEVICE) -mtr $@ $< 46 | 47 | %_tb: %_tb.v %.v 48 | iverilog -o $@ $^ 49 | 50 | %_tb.vcd: %_tb 51 | vvp -N $< +vcd=$@ 52 | 53 | %_syn.v: %.blif 54 | yosys -p 'read_blif -wideports $^; write_verilog $@' 55 | 56 | %_syntb: %_tb.v %_syn.v 57 | iverilog -o $@ $^ `yosys-config --datdir/ice40/cells_sim.v` 58 | 59 | %_syntb.vcd: %_syntb 60 | vvp -N $< +vcd=$@ 61 | 62 | prog: $(PROJ).bin 63 | tinyprog -p $< 64 | 65 | sudo-prog: $(PROJ).bin 66 | @echo 'Executing prog as root!!!' 67 | sudo tinyprog -p $< 68 | 69 | clean: 70 | rm -f $(PROJ).blif $(PROJ).asc $(PROJ).rpt $(PROJ).bin 71 | 72 | .SECONDARY: 73 | .PHONY: all prog clean 74 | -------------------------------------------------------------------------------- /hardware/reference/README.md: -------------------------------------------------------------------------------- 1 | # uCISC Hardware Implementation 2 | 3 | The reference hardware implementation uses [project icestorm](http://www.clifford.at/icestorm/) 4 | to target the [TinyFPGA Bx board](https://tinyfpga.com/). As of this writing, 5 | the CPU has most of the functionality in the specs. It is able to do basic 6 | animations with LEDs (See [knight.ucisc](../examples/knight.ucisc)) and compute 7 | [fibonacci numbers](../examples/fib.ucisc). The contents of pc and r1 are sent 8 | to output pins you can hook up to LEDs to see the results (See 9 | [reference/top.v](reference/top.v) for the pinout - don't forget current 10 | limiting resistors on your LEDs). 11 | 12 | #### Basic Architecture 13 | 14 | The CPU is a 4 stage reference implementation broken up into the following 15 | stages: 16 | 17 | * Stage 0: Store result, load next instruction from memory 18 | * Stage 1: Load immediate from memory 19 | * Stage 2: Load source value from memory, or compute source from registers 20 | * Stage 3: Load dest value from memory, or compute dest from registers 21 | 22 | It has all 6 general purpose registers. 23 | 24 | Not implemented: 25 | * Manipulating the flags register other than as a result of the ALU calculation. 26 | * Manipulating the interrupt register 27 | * Memory banking for devices 28 | 29 | #### Usage 30 | 31 | 1. Follow the [project icestorm](http://www.clifford.at/icestorm/) install 32 | instructions for the yosys toolchain. 33 | 34 | 2. Compile your uCISC code to reference/prog.hex. You can use the 35 | [uCISC kotlin emulator](https://github.com/grokthis/ucisc-kotlin) for this. If 36 | you follow the install instructions there, you can run something like 37 | `ucisc -c > reference/prog.hex` to compile your code. 38 | 39 | 3. From the reference directory, do `make clean` and `make prog` with the 40 | TinyFPGA Bx board plugged into your computer. Make sure the bootloader on the 41 | FPGA is running. You may need `make sudo-prog` if your user doesn't have 42 | permissions to connect to the board. 43 | 44 | Note: You will want to hook a reset button to pin 2 with a pull down resistor. 45 | Setting reset to 3.3v will start the program over. The bootstrap process isn't 46 | as clean as I would like and sometimes program start doesn't work immediately 47 | after bootstrap and you need to reset it once. I should be able to work this 48 | out in a future release. 49 | 50 | #### Tests 51 | 52 | Install [Icarus Verilog](http://iverilog.icarus.com/) to run the tests. Then, from 53 | the reference directory, run `./run_tests` to run all tests. Note any warnings, 54 | compile errors or test failures in the output. 55 | 56 | #### Status 57 | 58 | Currently, the implementation takes about 25-35% of the resources on the 59 | Bx board, not including BRAMs of which I use all 32. I have not included 60 | devices or division in the ALU yet. In theory there is room for 2 CPUs with 61 | 4k x 16 block memory each and a couple of simple devices if you leave out 62 | the division opcode. 63 | 64 | I have successfully run at a full 16MHz without division and 8MHz with, but 65 | I may not have hit the critical long path yet with my limited testing. Time 66 | will tell, though fib(24) does push a lot of additions and memory operations 67 | through the processor. -------------------------------------------------------------------------------- /hardware/reference/prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0001 4640 0000 464a 0001 4635 0002 0010 fffc 4545 0001 0010 fff8 4540 4000 2 | 464a 0001 4635 0002 0010 fffc 4546 0001 0010 fff8 4540 0002 0040 ffe8 -------------------------------------------------------------------------------- /hardware/reference/run_tests: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | 4 | iverilog -o test_bench \ 5 | test/defines.v \ 6 | src/dff.v test/dff_tb.v 7 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 8 | echo "Found $FAILURES failures in dff_tb.v." 9 | 10 | iverilog -o test_bench \ 11 | test/defines.v \ 12 | src/memory_block.v test/memory_block_tb.v 13 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 14 | echo "Found $FAILURES failures in memory_block_tb.v." 15 | 16 | iverilog -o test_bench \ 17 | test/defines.v \ 18 | src/alu.v test/alu_tb.v 19 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 20 | echo "Found $FAILURES failures in alu_tb.v." 21 | 22 | iverilog -o test_bench \ 23 | test/defines.v \ 24 | src/effect_decoder.v test/effect_decoder_tb.v 25 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 26 | echo "Found $FAILURES failures in effect_decoder_tb.v." 27 | 28 | iverilog -o test_bench \ 29 | test/defines.v \ 30 | src/uart_tx.v test/uart_tx_tb.v 31 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 32 | echo "Found $FAILURES failures in uart_tx_tb.v." 33 | 34 | iverilog -o test_bench \ 35 | test/defines.v \ 36 | src/alu.v \ 37 | src/dff.v \ 38 | src/effect_decoder.v \ 39 | src/memory_block.v \ 40 | src/parallel_buffer.v \ 41 | src/uart_tx.v \ 42 | src/uart_rx.v \ 43 | src/uart_device.v \ 44 | src/devices.v \ 45 | src/cpu.v test/cpu_tb.v 46 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 47 | echo "Found $FAILURES failures in cpu_tb.v." 48 | 49 | #iverilog -o test_bench \ 50 | # test/defines.v \ 51 | # src/parallel_buffer.v \ 52 | # src/uart_tx.v \ 53 | # src/uart_device.v test/uart_device_tb.v 54 | #FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 55 | #echo "Found $FAILURES failures in uart_device_tb.v." 56 | 57 | iverilog -o test_bench \ 58 | test/defines.v \ 59 | src/uart_rx.v test/uart_rx_tb.v 60 | FAILURES=$(vvp test_bench | grep -c "ASSERTION FAILED") 61 | echo "Found $FAILURES failures in uart_rx_tb.v." 62 | -------------------------------------------------------------------------------- /hardware/reference/src/alu.v: -------------------------------------------------------------------------------- 1 | module alu( 2 | input [15:0] source, 3 | input [15:0] destination, 4 | input [3:0] op_code, 5 | input [15:0] flags, 6 | output [15:0] result_out, 7 | output [15:0] flags_out, 8 | output write_flags 9 | ); 10 | 11 | parameter DIVISION = 0; 12 | 13 | wire [31:0] mult_result = source * destination; 14 | 15 | wire [31:0] signed_shift_destination = { {16{flags[8] & destination[15]}}, destination }; 16 | assign result_out = result[15:0]; 17 | wire carry = result[16]; 18 | wire [16:0] result = 19 | //Bit operations 20 | op_code == 4'h0 ? source : // Copy 21 | op_code == 4'h1 ? source & destination : // AND 22 | op_code == 4'h2 ? source | destination : // OR 23 | op_code == 4'h3 ? source ^ destination : // XOR 24 | op_code == 4'h4 ? ~source : // inverse 25 | 26 | //Shift operations 27 | op_code == 4'h5 ? destination << source : // Shift left 28 | // shift signed/unsigned by sign flag 29 | op_code == 4'h6 ? source > 16'hF ? {16{flags[8] & destination[15]}} : signed_shift_destination >> source[3:0] : 30 | op_code == 4'h7 ? { source[7:0], source[15:8] } : // Swap 31 | op_code == 4'h8 ? { source[15:8], 8'h00 } : // High byte 32 | op_code == 4'h9 ? { 8'h00, source[7:0] } : // Low byte 33 | 34 | op_code == 4'hA ? destination + source : // Add 35 | op_code == 4'hB ? destination - source : // Subtract 36 | op_code == 4'hC ? mult_result[15:0] : // Multiply 37 | op_code == 4'hD ? mult_result[31:16] : // Multiply upper word 38 | op_code == 4'hE ? destination + source + flags[2] : // Add with carry 39 | 0; // TBD 40 | 41 | wire zero = result[15:0] == 15'h0; 42 | wire negative = result[15]; 43 | wire overflow = carry; 44 | wire divide_error = op_code == 4'hD && source == 16'h0; 45 | 46 | assign flags_out = { flags[15:5], divide_error, overflow, carry, negative, zero }; 47 | assign write_flags = op_code != 4'h0; 48 | endmodule 49 | -------------------------------------------------------------------------------- /hardware/reference/src/devices.v: -------------------------------------------------------------------------------- 1 | module devices ( 2 | input clock, 3 | input write_enable, 4 | input [15:0] address, 5 | input [15:0] data_in, 6 | input rx, 7 | output reg [15:0] data_out, 8 | output tx, 9 | output [15:0] peek 10 | ); 11 | 12 | wire control = address[15:12] == 4'h0; 13 | wire [7:0] target_device = control ? address[11:4] : address[15:8]; 14 | 15 | always @(posedge clock) begin 16 | data_out <= 17 | target_device == 8'h2 ? uart_data_out : 18 | 16'h0; 19 | end 20 | 21 | wire [15:0] uart_data_out; 22 | uart_device #(.DEVICE_ID(16'h100)) uart_device( 23 | .clock(clock), 24 | .write_enable(write_enable & target_device == 8'h2), 25 | .control(control), 26 | .address(address[7:0]), 27 | .data_in(data_in), 28 | .rx(rx), 29 | .data_out(uart_data_out), 30 | .tx(tx), 31 | .peek(peek) 32 | ); 33 | 34 | endmodule 35 | -------------------------------------------------------------------------------- /hardware/reference/src/dff.v: -------------------------------------------------------------------------------- 1 | module dff( 2 | input clock, 3 | input [WIDTH-1:0] d, 4 | input async_reset, 5 | input enable, 6 | output reg [WIDTH-1:0] q 7 | ); 8 | parameter WIDTH = 1; 9 | parameter INIT = {WIDTH{1'b0}}; 10 | 11 | initial q = INIT; 12 | 13 | always @ (posedge clock or posedge async_reset) 14 | if (async_reset) begin 15 | q <= INIT; 16 | end else if (enable == 1) begin 17 | q <= d; 18 | end 19 | endmodule -------------------------------------------------------------------------------- /hardware/reference/src/effect_decoder.v: -------------------------------------------------------------------------------- 1 | module effect_decoder ( 2 | input [15:0] flags, 3 | input [2:0] effect, 4 | output store 5 | ); 6 | assign store = 7 | effect == 3'h0 ? flags[0] : 8 | effect == 3'h1 ? ~flags[0] : 9 | effect == 3'h2 ? flags[1] : 10 | effect == 3'h3 ? ~flags[1] & ~flags[0] : 11 | effect == 3'h4 ? 1 : 12 | effect == 3'h5 ? flags[3] : 13 | effect == 3'h6 ? flags[4] : 14 | 0; 15 | 16 | endmodule 17 | -------------------------------------------------------------------------------- /hardware/reference/src/memory_block.v: -------------------------------------------------------------------------------- 1 | module memory_block ( 2 | input clock, 3 | input write_enable, 4 | input [15:0] read_address, 5 | input [15:0] write_address, 6 | input [15:0] data_in, 7 | output reg [15:0] data_out 8 | ); 9 | 10 | parameter WIDTH = 13; 11 | parameter mem_depth = 1 << WIDTH; 12 | parameter MEM_INIT_FILE = "prog.hex"; 13 | 14 | reg [15:0] mem[mem_depth-1:0]; 15 | 16 | initial begin 17 | if (MEM_INIT_FILE != "") begin 18 | $readmemh(MEM_INIT_FILE, mem); 19 | end 20 | end 21 | 22 | always @(posedge clock) begin 23 | if(write_enable) 24 | mem[write_address[WIDTH-1:0]] <= data_in; 25 | 26 | data_out <= mem[read_address[WIDTH-1:0]]; 27 | end 28 | 29 | endmodule -------------------------------------------------------------------------------- /hardware/reference/src/parallel_buffer.v: -------------------------------------------------------------------------------- 1 | module parallel_buffer( 2 | input clock, 3 | input [WIDTH-1:0] data_in, 4 | input write_in, 5 | input next_ready, 6 | output write_ready, 7 | output reg [WIDTH-1:0] data_out, 8 | output reg write_out 9 | ); 10 | parameter WIDTH = 8; 11 | initial write_out = 0; 12 | 13 | assign write_ready = ~write_out | next_ready; 14 | 15 | always @(posedge clock) begin 16 | if (write_ready & write_in) begin 17 | data_out <= data_in; 18 | write_out <= 1'b1; 19 | end else if (write_out & next_ready) begin 20 | data_out <= 0; 21 | write_out <= 1'b0; 22 | end 23 | end 24 | endmodule -------------------------------------------------------------------------------- /hardware/reference/src/uart_device.v: -------------------------------------------------------------------------------- 1 | module uart_device( 2 | input clock, 3 | input write_enable, 4 | input control, 5 | input [7:0] address, 6 | input [15:0] data_in, 7 | input rx, 8 | output [15:0] data_out, 9 | output tx, 10 | output [15:0] peek 11 | ); 12 | 13 | assign peek = control_read; 14 | 15 | parameter DEVICE_ID = 16'h0; 16 | parameter DEVICE_TYPE = 8'h4; 17 | 18 | wire control_write = control & write_enable; 19 | wire [3:0] control_address = address[3:0]; 20 | wire [7:0] rx_data_out; 21 | wire rx_data_ready; 22 | 23 | wire [15:0] control_read = 24 | control_address == 4'h0 ? DEVICE_ID : 25 | control_address == 4'h1 ? { flags, DEVICE_TYPE } : 26 | control_address == 4'h2 ? baud_clock_divider : 27 | control_address == 4'h4 ? { 8'h0, rx_data_out } : 28 | 16'h0; 29 | 30 | assign data_out = control ? control_read : 16'h0; 31 | 32 | wire in_progress = ~write_ready | ~ready_p1p2 | ~tx_ready; 33 | wire [7:0] flags = { 4'h1, 1'b0, in_progress, rx_data_ready, write_ready }; 34 | 35 | reg [15:0] baud_clock_divider; 36 | initial baud_clock_divider = 16'h8B; // 115200 baud 37 | 38 | wire buffer_write_en = control_write & control_address == 4'h3; 39 | 40 | always @(posedge clock) begin 41 | if (control_write & control_address == 4'h2) 42 | baud_clock_divider <= data_in; 43 | end 44 | 45 | wire write_p1p2; 46 | wire ready_p1p2; 47 | wire [7:0] data_p1p2; 48 | wire tx_ready; 49 | wire [7:0] tx_data; 50 | wire tx_write; 51 | 52 | wire write_ready; 53 | parallel_buffer #(.WIDTH(8)) pb1( 54 | .clock(clock), 55 | .data_in(data_in[7:0]), 56 | .write_in(buffer_write_en), 57 | .next_ready(ready_p1p2), 58 | .write_ready(write_ready), 59 | .data_out(data_p1p2), 60 | .write_out(write_p1p2) 61 | ); 62 | 63 | parallel_buffer #(.WIDTH(8)) pb2( 64 | .clock(clock), 65 | .data_in(data_p1p2), 66 | .write_in(write_p1p2), 67 | .next_ready(tx_ready), 68 | .write_ready(ready_p1p2), 69 | .data_out(tx_data), 70 | .write_out(tx_write) 71 | ); 72 | 73 | uart_tx uart_tx( 74 | .clock(clock), 75 | .clock_divider(baud_clock_divider), 76 | .data_in(tx_data), 77 | .write_en(tx_write), 78 | .data_ready(tx_ready), 79 | .tx(tx) 80 | ); 81 | 82 | wire [15:0] rx_buffer_out; 83 | 84 | uart_rx uart_rx( 85 | .clock(clock), 86 | .clock_divider(baud_clock_divider), 87 | .read_en(control_address == 4'h4 & control_write), 88 | .rx(rx), 89 | .data_ready(rx_data_ready), 90 | .data_out(rx_data_out) 91 | ); 92 | endmodule 93 | -------------------------------------------------------------------------------- /hardware/reference/src/uart_rx.v: -------------------------------------------------------------------------------- 1 | module uart_rx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input read_en, 5 | input rx, 6 | output reg data_ready, 7 | output reg [WIDTH-1:0] data_out 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | initial data_ready = 0; 12 | 13 | reg reading = 0; // Are we currently reading a byte? 14 | reg [15:0] clock_counter = 0; // Counts up to the clock divider 15 | reg [3:0] bit_number; // Which bit are we currently reading? 16 | reg [7:0] buffer = 8'h0; // Shift buffer for incoming bits 17 | reg buffer_ready = 0; // 1 if buffer has a valid byte value for read 18 | 19 | always @(posedge clock) begin 20 | if (~reading) begin 21 | // Bit number stays at zero while waiting for the next byte 22 | bit_number <= 4'h0; 23 | if (~rx) begin 24 | // RX went low, count to half the baud clock width and sample 25 | clock_counter <= clock_divider[15:1] + 1'b1; 26 | reading <= 1'b1; 27 | end 28 | end else begin 29 | if (clock_counter == clock_divider) begin 30 | // take a sample 31 | if (bit_number == 4'h0) begin 32 | // We are still in the start bit, init details 33 | buffer_ready <= 1'b0; // About to write to this 34 | bit_number <= bit_number + 1; 35 | // Clock counter starts at 1 indexed so you can calc 36 | // the divider value based without accounting for zero bit 37 | clock_counter <= 16'h1; 38 | end else if (bit_number == 4'h9) begin 39 | // Stop bit, if rx is low, we took too long, read right away 40 | reading = ~rx; 41 | if (~rx) begin 42 | // We took too long on the last byte, this time 43 | // Remove one clock cycle and go straight into the 44 | // next start bit 45 | clock_counter <= clock_divider[15:2]; 46 | bit_number <= 4'h0; 47 | end 48 | end else begin 49 | if (bit_number == 4'h8) begin 50 | // We read all 8 bits, byte is ready to move into 51 | // the output value 52 | buffer_ready <= 1'b1; 53 | end 54 | clock_counter <= 16'h1; 55 | bit_number <= bit_number + 1; 56 | buffer = { rx, buffer[7:1] }; 57 | end 58 | end else begin 59 | clock_counter <= clock_counter + 1; 60 | end 61 | end 62 | end 63 | 64 | // make sure buffer ready goes low at least once between reads 65 | // to ensure we don't read the same value twice 66 | reg new_data = 0; 67 | always @(posedge clock) begin 68 | if (~data_ready & buffer_ready & new_data) begin 69 | data_out <= buffer; 70 | data_ready <= 1'b1; 71 | new_data <= 1'b0; 72 | end else if (read_en) begin 73 | data_ready <= 1'b0; 74 | end else if (~buffer_ready) begin 75 | new_data <= 1'b1; 76 | end 77 | end 78 | endmodule -------------------------------------------------------------------------------- /hardware/reference/src/uart_tx.v: -------------------------------------------------------------------------------- 1 | module uart_tx( 2 | input clock, 3 | input [15:0] clock_divider, 4 | input [WIDTH-1:0] data_in, 5 | input write_en, 6 | output data_ready, 7 | output tx 8 | ); 9 | parameter WIDTH = 8; 10 | 11 | reg [15:0] clock_count; 12 | initial clock_count = 0; 13 | 14 | reg [WIDTH+1:0] data; 15 | reg [3:0] shift_remaining; 16 | initial shift_remaining = 0; 17 | assign tx = data_ready | data[0]; 18 | assign data_ready = shift_remaining == 0; 19 | 20 | always @(posedge clock) begin 21 | if (data_ready & write_en) begin 22 | data <= { 1'b1, data_in, 1'b0 }; 23 | shift_remaining = WIDTH + 2; 24 | clock_count <= 0; 25 | end else if (~data_ready) begin 26 | if (clock_count == clock_divider) begin 27 | shift_remaining = shift_remaining - 1; 28 | data <= { 1'b1, data[WIDTH:1] }; 29 | clock_count <= 0; 30 | end else begin 31 | clock_count = clock_count + 1; 32 | end 33 | end 34 | end 35 | endmodule -------------------------------------------------------------------------------- /hardware/reference/test/defines.v: -------------------------------------------------------------------------------- 1 | `define assert(signal, value) if (signal !== value) begin $display("ASSERTION FAILED in %m: signal != value"); $finish; end 2 | -------------------------------------------------------------------------------- /hardware/reference/test/dff_tb.v: -------------------------------------------------------------------------------- 1 | module dff_tb; 2 | 3 | // Setup registers for the DFF inputs 4 | reg clock; 5 | reg [15:0] d; 6 | reg a_reset; 7 | reg enable; 8 | 9 | // Setup a wire for the dff output "q" 10 | wire [15:0] q; 11 | 12 | // Instantiate the unit under test 13 | dff #(.WIDTH(16)) dff( 14 | .clock(clock), 15 | .d(d), 16 | .async_reset(a_reset), 17 | .enable(enable), 18 | .q(q) 19 | ); 20 | 21 | initial begin 22 | // Initialize standard setup 23 | clock = 0; 24 | d = 16'h0; 25 | a_reset = 0; 26 | enable = 1; 27 | 28 | #20 d = 16'hFFFF; 29 | // Should capture on positive clock edge 30 | #20 clock = 1; 31 | #1 `assert(q, 16'hFFFF); 32 | 33 | // Should not capture without positive clock edge 34 | #20 d = 16'h1111; 35 | #1 `assert(q, 16'hFFFF); 36 | #20 clock = 0; 37 | #1 `assert(q, 16'hFFFF); 38 | 39 | // Reset sets output and holds output at 0 40 | #20 a_reset = 1; 41 | #1 `assert(q, 16'h0000); 42 | #20 clock = 1; 43 | #1 `assert(q, 16'h0000); 44 | #20 a_reset = 0; 45 | #1 `assert(q, 16'h0000); 46 | 47 | // Enable held at 0 makes DFF unresponsive to clock 48 | #20 d = 16'hF42F; 49 | #1 `assert(q, 16'h0000); 50 | enable = 0; 51 | #1 `assert(q, 16'h0000); 52 | #20 clock = 0; 53 | #1 `assert(q, 16'h0000); 54 | #20 clock = 1; 55 | #1 `assert(q, 16'h0000); 56 | 57 | // Enable assertion doesn't capture input 58 | #20 enable = 1; 59 | #1 `assert(q, 16'h0000); 60 | #20 clock = 0; 61 | #1 `assert(q, 16'h0000); 62 | // Positive edge captures input 63 | #20 clock = 1; 64 | #1 `assert(q, 16'hF42F); 65 | end 66 | 67 | initial begin 68 | $monitor("clock=%d, d=%04x, async_reset=%d, enable=%d, q=%04x", clock, d, a_reset, enable, q); 69 | end 70 | endmodule -------------------------------------------------------------------------------- /hardware/reference/test/effect_decoder_tb.v: -------------------------------------------------------------------------------- 1 | module effect_decoder_tb; 2 | 3 | // Setup registers for the inputs 4 | reg [15:0] flags; 5 | reg [2:0] effect; 6 | 7 | // Setup a wire for the outputs 8 | wire store; 9 | 10 | // Instantiate the unit under test 11 | effect_decoder effect_decoder( 12 | .flags(flags), 13 | .effect(effect), 14 | .store(store) 15 | ); 16 | 17 | initial begin 18 | // Initialize standard setup 19 | flags = 16'h0; 20 | effect = 3'h0; 21 | 22 | #1 `assert(store, 0); 23 | // TODO Implement these tests 24 | end 25 | 26 | initial begin 27 | $monitor("flags=%04x, effect=%d, store=%x", flags, effect, store); 28 | end 29 | endmodule -------------------------------------------------------------------------------- /hardware/reference/test/memory_block_tb.v: -------------------------------------------------------------------------------- 1 | module memory_block_tb; 2 | 3 | // Setup registers for the inputs 4 | reg clock; 5 | reg write_enable; 6 | reg [15:0] read_address; 7 | reg [15:0] write_address; 8 | reg [15:0] data_in; 9 | 10 | // Setup a wire for the output 11 | wire [15:0] data_out; 12 | 13 | // Instantiate the unit under test 14 | memory_block #(.WIDTH(14), .MEM_INIT_FILE("test/test_prog.hex")) memory_block( 15 | .clock(clock), 16 | .write_enable(write_enable), 17 | .read_address(read_address), 18 | .write_address(write_address), 19 | .data_in(data_in), 20 | .data_out(data_out) 21 | ); 22 | 23 | initial begin 24 | // Initialize standard setup 25 | clock = 0; 26 | write_enable = 0; 27 | read_address = 16'h0; 28 | write_address = 16'h0; 29 | data_in = 16'h0; 30 | 31 | // Read initial data from file 32 | #20 clock = 1; 33 | #1 `assert(data_out, 16'h4540); 34 | #20 clock = 0; 35 | 36 | // Set output to 0, a known value 37 | #20 write_enable = 1; 38 | #20 clock = 1; 39 | // data written 40 | #20 clock = 0; 41 | #20 clock = 1; 42 | // data read 43 | #1 `assert(data_out, 16'h0000); 44 | 45 | #20 clock = 0; 46 | #20 clock = 1; 47 | #1 write_enable = 0; 48 | #1 data_in = 16'hAAAA; 49 | #20 clock = 0; 50 | #20 clock = 1; 51 | #1 `assert(data_out, 16'h0000); 52 | 53 | // Memory is pseudo dual port, doesn't immediately write through 54 | #1 data_in = 16'hAAAA; 55 | #1 write_enable = 1; 56 | #20 clock = 0; 57 | #20 clock = 1; 58 | #1 `assert(data_out, 16'h0000); 59 | #1 write_enable = 0; 60 | #20 clock = 0; 61 | // Doesn't read on negative edge 62 | #1 `assert(data_out, 16'h0000); 63 | #20 clock = 1; 64 | // Only reads on positive edge 65 | #1 `assert(data_out, 16'hAAAA); 66 | end 67 | 68 | initial begin 69 | $monitor( 70 | "clock=%04x, write_enable=%d, read_address=%04x, write_address=%04x, data_in=%04x, data_out=%04x", 71 | clock, write_enable, read_address, write_address, data_in, data_out); 72 | end 73 | endmodule -------------------------------------------------------------------------------- /hardware/reference/test/test_prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0000 41c0 07ff 1540 0000 4540 0000 4640 ffff 61c0 0000 1540 0000 4540 0000 2 | 41c0 0400 17c0 0000 51c0 0000 1540 0000 4540 0000 41c0 0400 41c0 000a 5640 0001 3 | 12c0 1000 1540 0000 0040 0000 -------------------------------------------------------------------------------- /hardware/reference/test/test_prog.ucisc: -------------------------------------------------------------------------------- 1 | # Specialized version of https://github.com/grokthis/ucisc-kotlin/tree/trunk/src/ucisc/test 2 | # designed to avoid halts and let the verilog simulator step through and verify state 3 | 4 | ##################### 5 | # Stack Setup Tests # 6 | ##################### 7 | 8 | testMaxImm: 9 | copy val 0 &stack 10 | copy val 2047 stack 0 push 11 | # expect r1 = FFFF 12 | copy r1 0 &r1 13 | # expect r1 = 2047 14 | 15 | # Begin instruction 4 16 | testMaxImmReg: 17 | copy val 0 &stack 18 | copy val 65535 &r2 19 | copy &r2 0 stack 0 push 20 | # expect r1 = FFFF 21 | copy r1 0 &r1 22 | # expect r1 = FFFF 23 | 24 | # Begin instruction 8 25 | testPopStack: 26 | copy val 0 &stack 27 | copy val 1024 stack 0 push 28 | # expect r1 = FFFF 29 | copy stack 0 &r3 pop 30 | # expect r1 = 0000 31 | copy &stack 0 stack 0 push 32 | # expect r1 = FFFF 33 | copy stack 0 &stack 34 | # expect r1 = 0000 35 | 36 | # Begin instruction 13 37 | testMemCopy1: 38 | copy val 0 &stack 39 | copy val 1024 stack 0 push 40 | # expect r1 = FFFF 41 | copy val 10 stack 0 push 42 | # expect r1 = FFFE 43 | copy &stack 1 &r2 44 | copy stack 0 r2 1 push 45 | # expect r1 = FFFE 46 | copy stack 0 &stack 47 | # expect r1 = 000A 48 | copy pc 0 pc -------------------------------------------------------------------------------- /hardware/reference/top.v: -------------------------------------------------------------------------------- 1 | module top( 2 | input CLK, 3 | input PIN_2, 4 | input PIN_3, 5 | output LED, 6 | output PIN_24, 7 | output PIN_23, 8 | output PIN_22, 9 | output PIN_21, 10 | output PIN_20, 11 | output PIN_19, 12 | output PIN_18, 13 | output PIN_17, 14 | output PIN_16, 15 | output PIN_15, 16 | output PIN_14, 17 | output PIN_13, 18 | output PIN_12, 19 | output PIN_11, 20 | output PIN_10, 21 | output PIN_9, 22 | output PIN_8, 23 | output PIN_7, 24 | output PIN_6, 25 | output PIN_5, 26 | output PIN_4, 27 | output PIN_1 28 | ); 29 | 30 | parameter address_width = 13; 31 | 32 | assign PIN_24 = r1[15]; 33 | assign PIN_23 = r1[14]; 34 | assign PIN_22 = r1[13]; 35 | assign PIN_21 = r1[12]; 36 | assign PIN_20 = r1[11]; 37 | assign PIN_19 = r1[10]; 38 | assign PIN_18 = r1[9]; 39 | assign PIN_17 = r1[8]; 40 | 41 | assign PIN_16 = r1[7]; 42 | assign PIN_15 = r1[6]; 43 | assign PIN_14 = r1[5]; 44 | assign PIN_9 = r1[4]; 45 | assign PIN_10 = r1[3]; 46 | assign PIN_11 = r1[2]; 47 | assign PIN_12 = r1[1]; 48 | assign PIN_13 = r1[0]; 49 | 50 | assign PIN_4 = pc[5]; 51 | assign PIN_5 = pc[4]; 52 | assign PIN_6 = pc[3]; 53 | assign PIN_7 = pc[2]; 54 | assign PIN_8 = pc[1]; 55 | assign PIN_1 = tx; 56 | wire rx = PIN_3; 57 | 58 | reg [24:0] slow_clock; 59 | initial slow_clock = 25'h0; 60 | 61 | always @(posedge CLK) begin // & PIN_1 62 | slow_clock <= slow_clock + 1; 63 | end 64 | 65 | wire clock = CLK; 66 | 67 | //reg clock; 68 | //initial clock = 0; 69 | //always @* begin 70 | // // Debounce clock buttons 71 | // clock <= PIN_1 | ((~PIN_2) & clock); 72 | //end 73 | //assign LED = store_reg; 74 | 75 | wire [1:0] step; 76 | wire [15:0] r1; 77 | wire [15:0] pc; 78 | wire tx; 79 | //assign LED = tx; 80 | 81 | cpu cpu( 82 | .clock_input(clock), 83 | .reset(PIN_2), 84 | .step(step), 85 | .r1_peek(r1), 86 | .pc_peek(pc), 87 | .tx(tx), 88 | .rx(rx) 89 | ); 90 | 91 | endmodule -------------------------------------------------------------------------------- /images/uCISC_circuitverse.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/grokthis/ucisc/3c40a288d26409a64cf192b4cbad135579a4e0ac/images/uCISC_circuitverse.png -------------------------------------------------------------------------------- /prog.hex: -------------------------------------------------------------------------------- 1 | 4540 0001 4640 0000 4d40 0040 4940 4001 5940 8000 464a 0001 467a 0000 0010 fffc 2 | 4543 0001 5940 8000 0040 fff6 -------------------------------------------------------------------------------- /prog.hex.a.hex: -------------------------------------------------------------------------------- 1 | 4540 4640 4d40 4940 5940 464a 467a 0010 4543 2 | 5940 0040 -------------------------------------------------------------------------------- /prog.hex.b.hex: -------------------------------------------------------------------------------- 1 | 0001 0000 0040 4001 8000 0001 0000 fffc 2 | 0001 8000 fff6 -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | rootProject.name = 'ucisc' 2 | 3 | include('tools') 4 | include('hardware:ecp5_reference') 5 | 6 | -------------------------------------------------------------------------------- /tools/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id 'application' 3 | id 'checkstyle' 4 | } 5 | 6 | application { 7 | mainClass = 'ucisc.tools.Utilities' 8 | } 9 | 10 | repositories { 11 | mavenCentral() 12 | } 13 | 14 | dependencies { 15 | testImplementation(platform('org.junit:junit-bom:5.7.1')) 16 | testImplementation('org.junit.jupiter:junit-jupiter') 17 | } 18 | 19 | test { 20 | useJUnitPlatform() 21 | testLogging { 22 | events "passed", "skipped", "failed" 23 | } 24 | } 25 | 26 | jar { 27 | manifest { 28 | attributes 'Main-Class': 'ucisc.tools.Utilities' 29 | } 30 | } -------------------------------------------------------------------------------- /tools/src/test/java/ucisc/tools/UtilitiesTest.java: -------------------------------------------------------------------------------- 1 | package ucisc.tools; 2 | 3 | import org.junit.jupiter.api.Test; 4 | 5 | /** 6 | * Tests for utilities command line interface. 7 | */ 8 | public class UtilitiesTest { 9 | @Test 10 | public void testRun() throws Exception { 11 | System.out.println("Hello from test."); 12 | Utilities.main(new String[0]); 13 | } 14 | } 15 | --------------------------------------------------------------------------------