├── .github └── dependabot.yml ├── .gitignore ├── Chad.vcxproj ├── LICENSE ├── Makefile ├── README.md ├── artyA7 ├── README.md ├── artydemo.f └── html │ ├── doc.css │ └── index.html ├── bin ├── README.md ├── chad.exe ├── freeglut.dll ├── gui.exe ├── isp.exe ├── splash.bmp └── term.exe ├── doc ├── ASIC.xlsx ├── ASICs.md ├── README.md ├── artyLCD.jpg ├── crypto.md ├── debug.md ├── forth.md ├── interrupts.md ├── io.md ├── isa.md ├── lcd.md ├── manifesto.md ├── mcu.png ├── sdcard.md ├── spif.md ├── stack.png └── strings.md ├── forth ├── ANSify │ └── ansify.f ├── README.md ├── api.f ├── bignum.f ├── compile.f ├── core.f ├── coreext.f ├── ctea.f ├── flash.f ├── frame.f ├── interpret.f ├── io_equs.f ├── more.f ├── myfont.bin ├── numout.f ├── redirect.f ├── tftlcd.f ├── tools.f └── wiki │ ├── README.md │ ├── wikiasm.txt │ ├── wikiforth.txt │ └── wikiroot.txt ├── guisim ├── README.md ├── TFTsim.c ├── TFTsim.h ├── clean.bat ├── freeglut.dll ├── freeglut.lib ├── gui.c ├── gui.h ├── gui.sln ├── gui.vcxproj ├── gui.vcxproj.filters ├── gui.vcxproj.user ├── include_glut │ ├── freeglut.h │ ├── freeglut_ext.h │ ├── freeglut_std.h │ └── glut.h └── main.cpp ├── myapp ├── README.md ├── html │ ├── doc.css │ └── index.html ├── myapp.bin └── myapp.f ├── src ├── README.md ├── _coproc.c ├── chad.c ├── chad.h ├── chaddefs.h ├── config.h ├── errors.c ├── flash.c ├── flash.h ├── gecko.c ├── gecko.h ├── iomap.c ├── iomap.h └── main.c ├── utility ├── README.md ├── fonts │ ├── fontcmp.f │ ├── graphics.f │ ├── make.f │ └── test.txt └── isp │ ├── isp.c │ ├── readme.md │ ├── rs232.c │ ├── rs232.h │ └── term.c └── verilog ├── README.md ├── boards ├── Efinix │ ├── README.md │ ├── demo_io.v │ ├── mcu_top.v │ ├── xyloni_chad.peri.xml │ ├── xyloni_chad.sdc │ ├── xyloni_chad.xml │ └── xyloni_chad_io.isf ├── LatticeECP5 │ ├── mcu_top.v │ └── mcutop.sdc ├── LatticeXP2 │ ├── Lattice_brevia2.lpf │ ├── README.md │ ├── clkgen.v │ ├── demo_io.v │ └── mcu_top.v ├── MAX10 │ ├── clkgen.ppf │ ├── clkgen.qip │ ├── clkgen.v │ ├── demo_io.v │ ├── mcu_top.v │ └── mcutop.sdc ├── Xilinx │ ├── README.md │ ├── demo_io.v │ ├── mcu_arty.v │ ├── mcu_arty.xdc │ └── tcl.txt └── iceSugar-Pro1.3 │ ├── README.md │ ├── clkgen.v │ ├── demo_io.v │ ├── dummy.v │ ├── iCESugarDemo_impl1.bit │ ├── mcu_top.v │ ├── mcu_top_tb.v │ └── top.lpf ├── peripherals └── lcdcon.v ├── rtl ├── cdc.v ├── chad.v ├── coproc.v ├── crc32.v ├── gecko.v ├── gpu.v ├── idivu.v ├── imultf.v ├── ishift.v ├── mcu.v ├── options.vh ├── prio_enc.v ├── sflash.v ├── spif.v ├── spram.v ├── stack.v └── uart.v └── testbench ├── cdc_tb.v ├── coproc_tb.v ├── crc32.v ├── fdata.bin ├── flashsim.v ├── gecko_tb.v ├── gpu_tb.v ├── idivu_tb.v ├── imultf_tb.v ├── ishift_tb.v ├── mcu_artyA7_tb.v ├── mcu_tb.v ├── nopll.v ├── peripherals └── lcdcon_tb.v ├── prio_enc_tb.v ├── s25fl064l.v ├── sflash_tb.v ├── spif_tb.v ├── uart_tb.v ├── uartsim.v ├── udata.bin └── usrmclk.v /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "NuGet" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | src/*.o 2 | src/*.d 3 | forth/chad 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Bradley Eckert 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | TARGET ?= ./forth/chad 2 | SRC_DIRS ?= ./src 3 | 4 | SRCS := $(shell \ 5 | find $(SRC_DIRS) -name [!_]*.cpp -or -name [!_]*.c -or -name [!_]*.s) 6 | OBJS := $(addsuffix .o,$(basename $(SRCS))) 7 | DEPS := $(OBJS:.o=.d) 8 | 9 | INC_DIRS := $(shell find $(SRC_DIRS) -type d) 10 | INC_FLAGS := $(addprefix -I,$(INC_DIRS)) 11 | 12 | CPPFLAGS ?= $(INC_FLAGS) -MMD -MP 13 | 14 | $(TARGET): $(OBJS) 15 | $(CC) $(LDFLAGS) $(OBJS) -o $@ $(LOADLIBES) $(LDLIBS) 16 | 17 | .PHONY: clean 18 | clean: 19 | $(RM) $(TARGET) $(OBJS) $(DEPS) 20 | 21 | -include $(DEPS) 22 | 23 | # On the Linux command line: 24 | # make creates chad and leaves a bunch of object files in /src 25 | # make clean deletes the intermediate files as well as chad 26 | 27 | # The executable is in ./forth. Run it by typing "./chad". 28 | 29 | # A newly installed Linux might be missing dev tools. Install them with: 30 | # apt install make 31 | # apt install gcc 32 | # make 33 | 34 | # Put sudo before everything if you haven't given yourself more permissions. 35 | 36 | -------------------------------------------------------------------------------- /artyA7/README.md: -------------------------------------------------------------------------------- 1 | # Sample Application 2 | 3 | This sample Forth app loads Forth code including a text interpreter (`quit` loop). 4 | 5 | It saves the output in several formats: 6 | 7 | - `.bin` is a binary image of the SPI flash with 16-byte boilerplate 8 | - `.txt` is the same image (sans boilerplate) in hex format for simulation 9 | - HTML documentation folder 10 | 11 | `chad` can boot and run the `.bin` file. 12 | If you program the data into a SPI flash, the synthesized MCU will boot and run it. 13 | 14 | If you look at the `.bin` file, you'll see several sections: 15 | 16 | - The 16-byte boilerplate: base sector, length, CRC32, and product ID 17 | - Boot code that initializes code and data memories 18 | - Dictionary headers 19 | - Text strings 20 | - Font bitmap data (in plaintext) 21 | 22 | -------------------------------------------------------------------------------- /artyA7/artydemo.f: -------------------------------------------------------------------------------- 1 | \ Application example for Arty A7 board with 320 x 480 LCD. 12/15/20 2 | 3 | \ To load: With your working directory here, type: 4 | \ ..\bin\gui include artydemo.f (in Windows), or 5 | \ ../bin/gui include artydemo.f (in Linux) 6 | \ If SPI flash is encrypted, for example, with `1 +bkey`, launch with: 7 | \ ..\bin\gui 1 +bkey boot artydemo.bin 8 | 9 | 10 | \ Put text high enough in flash memory that it won't get clobbered by 11 | \ boot code and headers. Should be a multiple of 4096. 12 | 13 | $6000 forg \ strings in flash start here 14 | $8000 equ fontDB \ font database location 15 | 16 | 1 +bkey \ encrypt boot record if not zero 17 | 2 +tkey \ encrypt text if not zero 18 | 34 equ BASEBLOCK \ leave space for A7-35T FPGA bitstream 19 | 20 | include ../forth/core.f 21 | include ../forth/coreext.f 22 | include ../forth/io_equs.f 23 | include ../forth/redirect.f 24 | include ../forth/frame.f 25 | include ../forth/numout.f 26 | include ../forth/compile.f 27 | include ../forth/flash.f 28 | include ../forth/interpret.f 29 | include ../forth/tftlcd.f 30 | include ../forth/bignum.f 31 | \ include ../forth/ctea.f 32 | 33 | 34 | \ Error handling 35 | 36 | [defined] quit [if] 37 | :noname ( error -- ) ?dup if quit then 38 | ; resolves throw \ quit handles the errors 39 | [else] 40 | :noname ( error -- ) ?dup if [ $4000 cells ] literal io! then 41 | ; resolves throw \ iomap.c sends errors to the Chad interpreter 42 | [then] 43 | 44 | \ Hardware loads code and data RAMs from flash. Upon coming out of reset, 45 | \ both are initialized. The PC can launch from 0 (cold). 46 | 47 | [defined] quit [if] 48 | 49 | : myapp ( -- ) 50 | [ $18 cells ] literal dup io@ \ read gp_i 51 | swap io! \ write top gp_o 52 | /tft dkred pink set-colors 53 | lcd page 140 test con \ test screem 54 | ." May the Forth be with you!" 55 | 0 quit 56 | ; 57 | 58 | ' myapp resolves coldboot 59 | 60 | \ You can now run the app with "cold" 61 | 62 | : hi ." 多么美丽的世界 " ; 63 | 64 | [then] 65 | 66 | \ Examples 67 | 68 | : fib ( n1 -- n2 ) 69 | dup 2 < if drop 1 exit then 70 | dup 1 - recurse 71 | swap 2 - recurse + ; 72 | 73 | \ Try 25 fib, then stats 74 | .( Total instructions: ) there . cr 75 | 76 | \ Save to a flash memory image 77 | [defined] lit, [if] \ if there's code for it... 78 | $2000 forg make-heads \ build headers in flash 79 | $0000 forg make-boot \ create a boot record in flash 80 | fontDB load-flash ../forth/myfont.bin \ add the fonts in raw binary 81 | 1 0. BASEBLOCK save-flash app.bin \ save to a 'chad' file you can boot 82 | 0 0. BASEBLOCK save-flash appraw.bin \ without boilerplate for Vivado 83 | 2 0. BASEBLOCK save-flash app.txt \ save as hex for flash sim model 84 | [then] 85 | 86 | \ You can now run the app with "boot myapp.bin" or a Verilog simulator. 87 | 88 | \ Now let's generate a language standard 89 | only forth 90 | gendoc ../forth/wiki/wikiforth.txt html/forth.html 91 | previous 92 | gendoc ../forth/wiki/wikiroot.txt html/root.html 93 | asm +order 94 | gendoc ../forth/wiki/wikiasm.txt html/asm.html 95 | only forth 96 | 97 | \ 0 there dasm \ dumps all code 98 | -------------------------------------------------------------------------------- /artyA7/html/doc.css: -------------------------------------------------------------------------------- 1 | 50 | 51 | .forth { 52 | font-weight: bold; 53 | font-family: monospace; 54 | } 55 | -------------------------------------------------------------------------------- /artyA7/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MyApp Reference 8 | 9 | 12 | 13 | 14 |

MyApp Reference

15 |
16 |

HTML documentation was generated by gendoc. 17 | See the source code of myapp.f. 18 | The generated files files are: 19 |

20 | 21 | 26 | 27 |

They are referenced by hyperlinked versions of each source file 28 | automatically generated by chad 29 | 30 |

41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /bin/README.md: -------------------------------------------------------------------------------- 1 | # Executables for Windows 2 | 3 | You should compile these executables yourself, which isn't too hard, 4 | rather than download them. But maybe you're lazy. 5 | Hopefully not too lazy to use a sandbox or a VM. 6 | An executable might not run on your computer if you didn't compile it there. 7 | Better to break out the old C compiler. 8 | 9 | - **chad.exe** is the `chad` simulator and Forth environment. 10 | - **gui.exe** is `chad` with a graphic window included. It's a VS19 project. 11 | - **term.exe** is a simple terminal emulator that you can run from the command line. 12 | - **isp.exe** is an In System Programming utility that uses the UART and SPIF. 13 | 14 | If you use Windows, try ConEmu as your (command line) terminal. It's wonderful. 15 | The keyboard buffer makes it easy to scroll back to previous line inputs, 16 | cut and paste, etc. It also displays UTF-8 and handles ANSI codes. 17 | PowerShell also works. 18 | -------------------------------------------------------------------------------- /bin/chad.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/chad.exe -------------------------------------------------------------------------------- /bin/freeglut.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/freeglut.dll -------------------------------------------------------------------------------- /bin/gui.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/gui.exe -------------------------------------------------------------------------------- /bin/isp.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/isp.exe -------------------------------------------------------------------------------- /bin/splash.bmp: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/splash.bmp -------------------------------------------------------------------------------- /bin/term.exe: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/bin/term.exe -------------------------------------------------------------------------------- /doc/ASIC.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/doc/ASIC.xlsx -------------------------------------------------------------------------------- /doc/README.md: -------------------------------------------------------------------------------- 1 | # Feature summaries 2 | 3 | - `crypto` SPI Flash encryption 4 | - `debug` Debugging tools 5 | - `forth` Differences from ANS Forth 6 | - `interrupts` How interrupts work 7 | - `io` I/O mapping 8 | - `isa` Instruction Set Architecture 9 | - `lcd` LCD module (ILI9341) simulator 10 | - `manifesto` Ramblings of a madman 11 | - `spif` SPI flash controller intelligent hub 12 | -------------------------------------------------------------------------------- /doc/artyLCD.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/doc/artyLCD.jpg -------------------------------------------------------------------------------- /doc/debug.md: -------------------------------------------------------------------------------- 1 | # Debugging options 2 | 3 | - `verbosity` *( u -- )* Sets the tracing options 4 | - `see` *( -- )* Disassemble a word 5 | - `dasm` *( addr len -- )* Disassembles a section of code 6 | - `sstep` *( addr steps -- )* Single step starting at *addr*. 7 | - `logsteps` *( steps -- )* Number of steps to log to "output.txt" 8 | 9 | ## verbosity 10 | 11 | There are four bit flags in the verbosity setting that control what the 12 | interpreter prints out. 13 | 14 | - `1` enables line printing. Each line of input text is echoed. 15 | - `2` enables printing of each blank delimited token and its stack effects. 16 | - `4` enables machine level instruction trace in the simulator. 17 | - `8` tracks the maximum stack depth 18 | - `16` prints out the source remaining after >IN. 19 | 20 | Options `1` and `2` (or both, 1|2 = `3`) show you what's going on in the 21 | chad interpreter (known in Forth as the QUIT loop). 22 | 23 | Option `4` is a machine level trace. 24 | You get a detailed output log to the terminal. 25 | If you use it, you are probably making your code too complex. 26 | Maybe you should re-factor or try something different. 27 | Stackrobatics usually means you need to re-think your approach. 28 | But it does look cool and it's an easy way to see what your code is doing 29 | in each instruction. 30 | 31 | ## see 32 | 33 | `see ` looks up a definition and disassembles it. 34 | When the instruction matches one of the predefined Forth primitives, 35 | it displays that Forth word instead of the packed ALU instruction. 36 | For example, 37 | 38 | ``` 39 | ok>see s>d 40 | s>d 41 | 166 0011 dup 42 | 167 0208 0< exit 43 | ok> 44 | ``` 45 | 46 | `dasm` can be used to disassemble a range of code. 47 | To disassemble all code, you could do `0 there dasm`. 48 | 49 | ## sstep 50 | 51 | `sstep` runs the simulator one step at a time for the number of steps 52 | or until the return stack underflows, whichever comes first. 53 | It does this by setting bit 2 in the verbosity setting during stepping. 54 | 55 | `4 verbosity` does the same thing. 56 | In that mode, invoking the simulator produces a log output listing. 57 | Make sure you use `0 verbosity` after getting the log because it's easy 58 | to trigger a lot more data than you want. 59 | 60 | ## logsteps 61 | 62 | `10000 logsteps cold` dumps the first 10000 simulation steps to "output.txt". 63 | The Verilog model, `chad.v`, has a LOGGING option that saves the same thing 64 | to "simlog.txt". Use a file comparison tool like WinMerge to see 65 | differences in simulation. It's best to test code before doing I/O because 66 | I/O is where the simulations start to differ. Real world peripherals 67 | create delays. For example, `emit` spins while waiting for the UART. 68 | 69 | # Machine level tracing 70 | 71 | There are various triggers you can use to instrument the code without being 72 | overwhelmed by data. 73 | These triggers are custom user instructions that only execute in the simulator. 74 | The instructions are: 75 | 76 | - `debug+` *( -- )* Turns on instruction level tracing. 77 | - `debug-` *( -- )* Turns off instruction level tracing. 78 | - `regs?` *( -- )* Triggers a register dump. 79 | - `/data` *( -- )* Clears data changes. 80 | - `data?` *( -- )* Displays all data changes since the last `/data` or `data?`. 81 | - `stacks?` *( -- )* Triggers a stack dump. 82 | 83 | `/data` and `data?` are used to find where data is being clobbered. 84 | Before the first use of `data?`, use `/data` to initialize it. 85 | Every time `data?` executes, it will display a list of changes to data space 86 | between address 0 and DP. 87 | -------------------------------------------------------------------------------- /doc/interrupts.md: -------------------------------------------------------------------------------- 1 | # Interrupts 2 | 3 | Interrupts are handled by modifying the return instruction. 4 | I call this method "lazy interrupts". 5 | 6 | IRQs in a lazy-interrupt system trade latency for overhead. 7 | Since an interrupt only happens upon a return, 8 | registers (such as carry flags) are free to be trashed. 9 | Critical sections don't need interrupt disabling. 10 | There is no need to disable ISRs while they are being serviced because the next 11 | ISR won’t be serviced until the next return. 12 | Multiple interrupts are naturally chained, with a priority encoder deciding who’s next. 13 | 14 | An interrupt request is serviced by modifying the PC instead of popping it from 15 | the return stack. This avoids excess return stack usage, which is important in a system 16 | that uses a hardware return stack. 17 | It also greatly simplifies verification compared to interrupts that can happen anytime. 18 | 19 | Interrupt vectors are fixed. An active interrupt has a jump to code. 20 | An inactive interrupt has a return instruction, which costs one cycle. 21 | Processor ports are `irq`, `ivec`, and `iack`. 22 | When `iack` = `1`, the return is being decoded and `irq` is being used to form 23 | the jump address. The priority encoder should decode `irq` and use `iack` 24 | to clear the corresponding request. 25 | 26 | Classic Forth systems have often used an ISR to handle time-critical data and then 27 | awakened a cooperative task to handle clean-up so as not to burden the interrupt system. 28 | The same idea applies to lazy interrupts. 29 | Once the time-critical part of the interrupt is taken care of, you can call 30 | non-time-critical parts of the ISR whose return instructions service the interrupt system. 31 | Admittedly, this costs a little return stack, so you need to make sure there's enough 32 | hardware stack to handle it. 33 | You could think of return instructions as an analog of Forth’s PAUSE. 34 | 35 | The maximum interrupt latency is easy enough to instrument in HDL simulation. 36 | A timer could track the maximum time between rising `irq` and `iack`. 37 | Since Forth executes `return` quite often, it's usually pretty low. 38 | 39 | ## mcu.v interrupt assignments 40 | 41 | - 1 = Raw cycle count overflow. ISR should increment the upper cell(s) of the cycle count. 42 | - 2 = UART transmitter is ready for another byte. 43 | Loading the next byte within one character period prevents any dead time in the output. 44 | - 3 = UART receiver is full. You have one character period to process it before overflow. 45 | -------------------------------------------------------------------------------- /doc/io.md: -------------------------------------------------------------------------------- 1 | # I/O map 2 | 3 | The Chad CPU connects to an I/O space modeled in `iomap.c`. 4 | 5 | The `_IORD_` field in an ALU instruction strobes `io_rd`. 6 | In the J1, input devices sit on (`mem_addr`,`io_din`). 7 | The `T->io[T]` field in an ALU instruction strobes `io_wr`. 8 | Output devices sit on (`mem_addr`,`dout`). 9 | 10 | See the `iomap.c` file for implementation details. 11 | 12 | A Wishbone bus is implemented by `spif.v` to connect to user peripherals. 13 | 14 | See the `spif` documentation for register details. 15 | -------------------------------------------------------------------------------- /doc/mcu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/doc/mcu.png -------------------------------------------------------------------------------- /doc/sdcard.md: -------------------------------------------------------------------------------- 1 | #SD card 2 | 3 | Currently on my to-do list: 4 | 5 | The LCD module plugged into the Arty-A7 board has a Micro-SD socket with four signal lines. 6 | Let's set up a 4-wire SPI interface. 7 | The wires are labeled: 8 | 9 | | Name | uSD pin | Usage | 10 | |--------|---------|-------------------| 11 | | sd_ss | 2 | SPI chip select | 12 | | sd_di | 3 | Data to SD card | 13 | | sd_do | 7 | Data from SD card | 14 | | sd_sck | 5 | SD card clock | 15 | | GND | 6 | | 16 | | 3.3V | 4 | | 17 | 18 | `sd_sck` will typically run at 10 to 25 MHz. 19 | 20 | The predominant SD card operations are block read and block write of 512 bytes each. 21 | The SPI should support 1-byte to 4-byte transfers using the Wishbone interface. 22 | When the transfer is finished, an ISR can be triggered to request the next word or 23 | software can just poll the status. The time to transfer 32 bits at 25 MHz is 1.3 usec 24 | which is 130 cycles at 100 MHz. It's probably okay to just poll. 25 | 26 | For a CPU with 24-bit cells, the ISR would write 3 bytes at a time, which doesn't 27 | exactly divide into 512. It's 170 cells and two bytes. The last write/read is a little short. 28 | 29 | ##Formatting 30 | 31 | Most SD cards are formatted with FAT16, FAT32, or exFAT by default. 32 | You'll want some kind of formatting even if you don't use it so that other computers will 33 | recognize the card when you plug it in. 34 | 35 | SD cards use sector virtualization to avoid quick burn-out from repeated update of FAT tables 36 | and other data at fixed sector numbers. In the physical NAND flash, the actual data could be anywhere. 37 | That means the SD card is already internally mapped for bad sectors. 38 | Formatting the SD card isn't going to find new bad sectors as they are already mapped out. 39 | So, FAT's cluster map is kind of redundant. 40 | 41 | A portion of the SD card can be left unallocated. The range of unallocated blocks can be obtained 42 | from the MBR and FAT tables. Then you could use a portion of the SD card as a FAT file system 43 | and the rest as a block system. 44 | 45 | ##Blocks 46 | 47 | The advantage of a block system is that updates to FAT can be avoided. You control the data as blocks. 48 | You can put log data at fixed blocks, edit blocks in-place as text, etc. Again, the SD card works around 49 | bad sectors for you. 50 | 51 | ##FAT File Systems 52 | 53 | I wrote a FAT File System once. It's not too complicated, but it's a bit involved. It's a lot of code 54 | just for compatibility with other computers. Maybe I don't want to use up that much code space. 55 | 56 | Read-only files would be easier to manage since there would be no need to change the FAT. 57 | Supporting only 8.3 filenames and the root directory (no folders) simplifies things further. 58 | -------------------------------------------------------------------------------- /doc/stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/doc/stack.png -------------------------------------------------------------------------------- /doc/strings.md: -------------------------------------------------------------------------------- 1 | # Strings in Chad 2 | 3 | Strings are stored in either SPI flash or RAM. 4 | Either way, they are a departure from ANS Forth. 5 | ANS Forth uses an *addr length* cell pair as a string specifier. 6 | It assumes that characters are addressable bytes. 7 | That's a lot to assume and codify in a standard 8 | whether it's a C standard or a Forth standard. 9 | 10 | The SPI flash is storage for boot code, text strings, dictionary headers, 11 | tables, and bitmaps. Characters in a SPI flash are a stream of bytes. 12 | You set the start address and read characters sequentially without 13 | further addressing. It's a different paradigm. 14 | 15 | Numbers are stored in SPI flash in big-endian format. 16 | Data elements such as strings and numbers are associated with a keystream 17 | so as to be encrypted. Hardware decrypts data from flash as it's read. 18 | 19 | `flash.f` is most of the implementation. 20 | 21 | -------------------------------------------------------------------------------- /forth/ANSify/ansify.f: -------------------------------------------------------------------------------- 1 | \ ANS harness for chad code 2 | 3 | \ This file allows chad code to compile and run on an ANS Forth with the exception 4 | \ of non-portable tricks like fall-through ( : x ... [ : y ... ; ). 5 | 6 | \ This bag of tricks includes: 7 | \ 1. Primitives from frame.f, useful for moving between stacks and memory. 8 | \ 2. Frame memory based local variables. 9 | \ 3. Chad's version of for next. 10 | 11 | [defined] -ansify [if] -ansify [else] marker -ansify [then] 12 | 1 constant test-ansify 13 | 14 | \ 1. Frame Stack 15 | 16 | 128 cells constant |framestack| 17 | 18 | variable frp \ frame stack pointer 19 | |framestack| buffer: frp0 \ bottom of frame stack 20 | 21 | : fpclear frp0 frp ! ; \ -- 22 | : >mem tuck ! cell + ; \ n a -- a' 23 | : mem> cell - dup @ ; \ a -- a' n 24 | 25 | \ Move data stack to memory 26 | \ "4 buf ds>mem" --> mem = x3 x2 x1 x0 4 trivial case: 0 27 | \ addr1----^ addr2----^ addr1----^ ^----addr2 28 | : ds>mem ( ... n addr1 -- addr2 ) \ ... n addr1 -- addr2 29 | over >r over if 30 | swap 0 do >mem loop 31 | else nip 32 | then r> swap >mem 33 | ; 34 | 35 | \ Move memory to data stack 36 | \ "mem>ds" --> mem = x3 x2 x1 x0 4 trivial case: 0 37 | \ addr2----^ addr1----^ addr2----^ ^----addr1 38 | : mem>ds ( addr1 -- ... addr2 ) \ addr1 -- ... addr2 39 | mem> dup if 40 | 0 do mem> swap loop exit 41 | then drop 42 | ; 43 | 44 | \ 2. Extended-scope local variables based on frame stack 45 | 46 | \ ANS Forth locals are nice, but their scope is limited to the current definition. 47 | \ Not very useful. They are practically syntactic sugar. Most experts eschew them. 48 | \ A proposed lexicon for locals is: 49 | 50 | \ begin-locals begins a locals scope and adds it to the search order 51 | \ end-locals ends the locals scope and removes it from the search order 52 | \ local ( u -- ) defines name that pushes an address onto the data stack 53 | \ (local) ( u -- a ) run-time portion of local 54 | \ /locals ( ... n m -- ) moves n cells onto the frame stack with m cells extra 55 | \ locals/ ( -- ) discards the frame 56 | 57 | \ example: 58 | \ module 59 | \ 0 cells local foo 60 | \ 1 cells local bar 61 | \ : first foo ? ; 62 | \ : second bar ? ; 63 | \ exportable 64 | \ : third ( bar foo -- ) 2 0 /locals foo bar locals/ ; 65 | \ end-module 66 | 67 | \ This strategy works best when there is one publicly used word in the scope. 68 | \ The other words are left visible 69 | 70 | variable localwid 71 | 72 | : module ( -- ) 73 | get-order wordlist dup localwid ! swap 1+ set-order 74 | definitions 75 | ; 76 | : exportable ( -- ) 77 | get-order 2 pick set-current set-order 78 | ; 79 | : end-module ( -- ) 80 | get-order nip 1- set-order definitions 81 | ; 82 | : (local) ( offset -- a ) 83 | frp @ swap - 84 | ; 85 | : local ( offset -- ) 86 | get-current >r 87 | localwid @ set-current create 2 cells + , 88 | r> set-current 89 | does> @ (local) 90 | ; 91 | : /locals ( ... n m -- ) 92 | dup >r cells frp +! frp @ 93 | ds>mem mem> r> + swap >mem frp ! 94 | ; 95 | : locals/ ( -- ) 96 | frp @ mem> negate cells + frp ! 97 | ; 98 | 99 | fpclear 100 | 101 | \ example: 102 | test-ansify [if] 103 | module 104 | 0 cells local foo 105 | 1 cells local bar 106 | cr .( foo is at ) foo . 107 | cr .( bar is at ) bar . 108 | : first cr ." the first local is " foo ? ; 109 | : second cr ." the second local is " bar ? ; 110 | exportable 111 | : test ( bar foo -- ) 112 | 2 0 /locals 113 | first second 114 | locals/ 115 | ; 116 | end-module 117 | 1 2 test 118 | [then] 119 | 120 | \ 3. for next 121 | 122 | : for 123 | postpone >R 124 | postpone BEGIN 125 | ; immediate 126 | : next 127 | postpone R> 128 | postpone 1- 129 | postpone DUP 130 | postpone >R 131 | postpone 0= 132 | postpone UNTIL 133 | postpone R> 134 | postpone DROP 135 | ; immediate 136 | 137 | test-ansify [if] 138 | : test4 3 for r@ . next ; 139 | cr test4 .( should be 3 2 1 ) 140 | [then] 141 | 142 | -------------------------------------------------------------------------------- /forth/README.md: -------------------------------------------------------------------------------- 1 | # Forth source files 2 | 3 | See the sample app in the `/myapp` folder. 4 | 5 | There's a `chad.exe` in the `/bin` folder for your convenience. 6 | Don't trust executables downloaded from the Internet except in a sandbox. 7 | Chad is easy enough to compile, but if you're into pre-compiled apps do yourself 8 | a favor and set up a VM or sandbox to limit their access to your PC. 9 | 10 | You should compile from source, which is safer for you and could reveal bugs for me. 11 | 12 | `myfont.bin` is generated by the `/utility/fonts` utility. 13 | -------------------------------------------------------------------------------- /forth/api.f: -------------------------------------------------------------------------------- 1 | \ API support 2 | 3 | there 4 | 5 | \ It would be better for APIexecute etc. to pack the `api` into xt. 6 | \ This would come into play if there are multiple instances of 7 | \ interpreters running, but since there isn't, `api` is global. 8 | 9 | : xt>API ( xt -- xxt ) 10 | api @ 13 lshift + 11 | ; 12 | 13 | : APIexecute ( xt -- ) 14 | xt>API xexec 15 | ; 16 | 17 | \ not used until the compiler is figured out, but... 18 | 19 | : APIcompile, ( xt -- ) 20 | xt>API lit, ['] xexec compile, 21 | ; 22 | 23 | there swap - .( ) . .( instructions used by api cache) cr 24 | -------------------------------------------------------------------------------- /forth/compile.f: -------------------------------------------------------------------------------- 1 | \ Compiler words 2 | 3 | there 4 | \ make-heads needs: 5 | \ {noop execute compile, lit, or doLitop noCompile} 6 | 7 | : c, here c! 1 allot ; \ 2.0580 c -- 8 | 9 | \ Compile to code RAM 10 | \ This might go away if compile to flash is possible. 11 | 12 | : !c ( n addr -- ) 13 | io'rxbusy io! \ set address 14 | io'txbusy io! \ write data 15 | ; 16 | 17 | variable lastinst \ load with $100 to inhibit exit change 18 | 19 | : ,c ( inst -- ) 20 | dup lastinst ! 21 | [char] c emit dup . \ display instead of compiling... 22 | cp @ !c 1 cp +! 23 | ; 24 | 25 | \ The LEX register is cleared whenever the instruction is not LITX. 26 | \ LITX shifts 11-bit data into LEX from the right. 27 | \ Full 16-bit and 32-bit data are supported with 2 or 3 inst. 28 | 29 | : extended_lit ( k11<<11 -- ) 30 | 11 rshift $7FF and $E000 + ,c 31 | ; 32 | 33 | cellbits 22 > [if] 34 | : lit, \ 2.5000 u -- 35 | dup $FFC00000 and if 36 | dup 11 rshift extended_lit 37 | dup extended_lit 38 | else 39 | dup $3FF800 and if 40 | dup extended_lit 41 | then 42 | then $7FF and 43 | $100 /mod 9 lshift + 44 | $F000 + ,c 45 | ; 46 | [else] 47 | : lit, \ 2.5000 u -- 48 | dup $3FF800 and if 49 | dup extended_lit 50 | then $7FF and 51 | $100 /mod 9 lshift + 52 | $F000 + ,c 53 | ; 54 | [then] 55 | 56 | : compile, \ 2.5010 xt -- 57 | dup $FFE000 and if 58 | dup 13 rshift $E000 + ,c \ litx 59 | then $1FFF and $C000 + ,c \ call 60 | ; 61 | : relast ( inst -- ) 62 | [char] r emit 63 | 0 invert cp +! ,c \ recompile the last instruction 64 | ; 65 | : exit, \ 2.5020 -- 66 | lastinst @ dup $810C and 0= if \ last ALU can accept return? 67 | $10C + relast exit then \ change to include a return 68 | $F000 2dup and = \ last literal? 69 | if $100 + relast exit then \ change to include a return 70 | drop $10C ,c \ plain return 71 | ; 72 | 73 | : doLitOp ( inst w -- 0 ) 74 | or ,c 0 75 | ; 76 | : noCompile ( -- ) 77 | -98 throw 78 | ; 79 | : InstExec ( inst -- ) 80 | [ cm-size 2 - ] literal tuck !c \ compile the instruction to end of 81 | $010C over 1+ !c execute \ code space and run it 82 | ; 83 | 84 | 85 | there swap - . .( instructions used by compiler) cr 86 | -------------------------------------------------------------------------------- /forth/coreext.f: -------------------------------------------------------------------------------- 1 | \ CORE EXT 2 | 3 | there 4 | 5 | 0 equ false \ 2.1000 -- false 6 | -1 equ true \ 2.1010 -- true 7 | 8 | : within over - >r - r> u< ; \ 2.1020 x xlo xhi -- flag 9 | : /string >r swap r@ + swap r> - ; \ 2.1030 addr1 u1 n -- addr2 u2 10 | : 0<> 0= 0= ; macro \ 2.1040 x y -- f 11 | : 0> negate 0< ; \ 2.1050 n -- f 12 | : u> swap u< ; \ 2.1060 u1 u2 -- flag 13 | : 2>r swap r> swap >r swap >r >r \ 2.1070 d -- | -- d 14 | ; no-tail-recursion 15 | : 2r> r> r> swap r> swap >r swap \ 2.1080 -- d | d -- 16 | ; no-tail-recursion 17 | : 2r@ r> r> r@ swap >r swap r@ swap >r \ 2.1090 -- d | d -- d 18 | ; no-tail-recursion 19 | : third >r >r dup r> swap r> swap ; \ 2.1100 x1 x2 x3 -- x1 x2 x3 x1 20 | : count dup 1+ swap c@ ; \ 2.1200 a -- a+1 c 21 | : @+ dup cell+ swap @ ; \ 2.1210 a -- a+cell u 22 | 23 | 24 | : 2@ _@ _dup@ swap cell + @ swap ; \ 2.1220 a-addr -- x1 x2 25 | : 2! _! cell + ! ; \ 2.1230 x1 x2 a-addr -- 26 | 27 | \ Add a cell to a double variable and carry into the upper part 28 | 29 | : 2+! \ 2.1240 n a-addr 30 | cell+ tuck @ +c over ! 31 | carry if 32 | -cell + 1 swap +! exit 33 | then drop 34 | ; 35 | 36 | : d+ >r swap >r +c carry r> + r> + ; \ 2.1130 d1 d2 -- d3 37 | : d- dnegate d+ ; \ 2.1140 d1 d2 -- d3 38 | : d2* swap 2* swap 2*c ; \ 2.1150 d1 -- d2 39 | : d= d- or 0= ; \ 2.1170 d1 d2 -- flag 40 | 41 | \ 2nip saves 1 inst by using w. Same trick isn't used with 2swap 42 | \ because carry, a, and b are not safe across calls. 43 | 44 | : 2swap rot >r rot r> ; \ 2.1190 abcd -- cdab 45 | : 2nip a! nip nip a ; 46 | : 2over >r >r 2dup r> r> 2swap ; 47 | : 3drop drop 2drop ; 48 | 49 | : du< \ 2.1180 ud1 ud2 -- flag 50 | rot 2dupxor 51 | if 2nip swap u< exit 52 | then 2drop u< \ hi part matches, test lo 53 | ; 54 | 55 | there swap - . .( instructions used by core ext) cr 56 | 57 | -------------------------------------------------------------------------------- /forth/ctea.f: -------------------------------------------------------------------------------- 1 | \ Chad Tiny Encryption Algorithm 9/19/20 BNE 2 | 3 | \ XTEA-inspired crypto algorithm for Chad. 4 | \ Uses 2-cell data and a 4-cell key. 5 | \ For 18-bit cells, it's 36-bit data and a 72-bit key. 6 | 7 | \ CTEA uses 71 instructions of code space. 8 | \ The numeric conversion pointer `hld` is used as temporary storage. 9 | 10 | there 11 | 12 | \ Note: Key lengths over 56-bit may be subject to export controls. 13 | \ The last cell in the table is 0 to make it a 54-bit key (if 18-bit cell). 14 | 15 | align 4 cells buffer: CTkey 16 | $179B9 equ CTdelta 17 | 18 equ CTrounds \ about 110 cycles per round 18 | 19 | : CTshift ( v -- v v' sum sum ) 20 | dup 2* 2* 2* 2* over 2/ 2/ 2/ 2/ 2/ xor \ could be custom instruction 21 | over + hld @ dup 22 | ; 23 | : CTcalcA CTshift [ ; 24 | : CTdokey 3 and cells CTkey + @ + xor rot swap ; 25 | : CTcalcB CTshift swapb 2/ 2/ 2/ CTdokey ; 26 | 27 | : encipher ( v0 v1 -- v0' v1' ) 28 | 0 hld ! 29 | CTrounds for 30 | CTcalcA + 31 | CTdelta hld +! 32 | CTcalcB + 33 | next 34 | swap 35 | ; 36 | : decipher ( v0 v1 -- v0' v1' ) 37 | [ CTdelta CTrounds * ] literal hld ! 38 | CTrounds for 39 | CTcalcB - 40 | [ CTdelta negate ] literal hld +! 41 | CTcalcA - 42 | next 43 | ; 44 | 45 | \ For SHA-256, there is support in the coprocessor for rotate right. 46 | 47 | hwoptions 4 and [if] \ hardware shifter? 48 | : ror32 \ d1 u -- d2 49 | a! [ $96 cotrig ] )dshift \ 32-bit rotate right, zero-extended 50 | ; 51 | [then] 52 | 53 | 54 | there swap - . .( instructions used by ctea) cr 55 | -------------------------------------------------------------------------------- /forth/frame.f: -------------------------------------------------------------------------------- 1 | \ Frame stack 9/10/20 BNE 2 | 3 | \ Placed near the top of data space, grows upward. 4 | 128 cells equ |framestack| 5 | 6 | \ The frame stack is for freeing up stack space for library code to run 7 | \ without overflowing the hardware stack. 8 | 9 | \ stack( ( n -- ) Pushes the return stack and most of the data stack 10 | \ except for the top n cells to the frame stack. 11 | 12 | \ )stack ( -- ) Restores the stack data saved by frame. 13 | 14 | there 15 | variable frp \ frame stack pointer 16 | variable frp1 \ temporary frame pointer 17 | 20 cells buffer: fpad \ frame pad 18 | 'tib @ |framestack| - equ frp0 \ bottom of frame stack 19 | \ See numout.f: frp0 is also the end of the numeric conversion buffer. 20 | 21 | : fpclear frp0 frp ! ; \ 2.2900 -- 22 | : >mem _! cell + ; \ 2.2910 n a -- a' 23 | : mem> -cell + _@ _dup@ ; \ 2.2920 a -- a' n 24 | 25 | \ Move data stack to memory 26 | \ "4 buf ds>mem" --> mem = x3 x2 x1 x0 4 trivial case: 0 27 | \ addr1----^ addr2----^ addr1----^ ^----addr2 28 | : ds>mem ( ... n addr1 -- addr2 ) \ 2.2930 ... n addr1 -- addr2 29 | over >r over if 30 | swap for >mem next 31 | else nip 32 | then r> swap >mem 33 | ; 34 | 35 | \ Move memory to data stack 36 | \ "mem>ds" --> mem = x3 x2 x1 x0 4 trivial case: 0 37 | \ addr2----^ addr1----^ addr2----^ ^----addr1 38 | : mem>ds ( addr1 -- ... addr2 ) \ 2.2940 addr1 -- ... addr2 39 | mem> dup if 40 | for mem> swap next exit 41 | then drop 42 | ; 43 | 44 | \ The `stack(` and `)stack` pair consumes 7 data and 5 return stack cells 45 | \ plus whatever is on the stack. At the time they are called, the stacks 46 | \ shouldn't be so full that calling them causes an overflow. 47 | 48 | \ Move the data stack to the frame stack, leaving n cells on top. 49 | \ The return stack is emptied except for one cell to keep the sim running. 50 | \ "11 22 33 44 55 2 stack(" --> FS = 33 22 11 3 0 stack = ( 44 55 ) 51 | \ fp----^ 52 | : stack( ( ... n -- x[n-1] ... x[0] ) \ 2.2950 n -- 53 | depth 54 | 2dup - 0< if 55 | r> frp @ spstat swapb 63 and ( RA fp rdepth ) 56 | -1 + 0 max \ leave a little on the return stack 57 | swap over ( RA rdepth fp cnt | ... ) 58 | begin dup while 1 - 59 | swap r> swap >mem swap \ push return stack to frame stack 60 | repeat 61 | drop >mem frp ! >r \ restore return address 62 | over - -1 + >r ( ... top | bottom ) 63 | fpad ds>mem frp1 ! \ save top of stack 64 | r> frp @ ds>mem frp ! \ move bottom of data stack to frame 65 | frp1 @ mem>ds drop \ restore top of stack 66 | else 67 | -4 throw \ not enough data on the stack 68 | then 69 | ; no-tail-recursion 70 | 71 | : )stack \ 2.2960 ? -- ? 72 | depth fpad ds>mem frp1 ! \ save whatever is on the stack 73 | frp @ mem>ds \ restore the old bottom 74 | r> swap mem> ( RA fp cnt ) 75 | begin dup while -1 + 76 | swap mem> >r swap ( RA fp n | ... x ) 77 | repeat 78 | drop frp ! >r \ restore return address 79 | frp1 @ mem>ds drop \ restore top 80 | ; no-tail-recursion 81 | 82 | \ Pick pushes the data stack to the frame stack, gets xu, and pops the data 83 | \ stack from the frame stack. 84 | : pick \ 2.2970 xu...x0 u -- xu...x0 xu 85 | frp @ ds>mem over >r mem>ds drop r> 86 | ; 87 | 88 | \ Index into the stack frame 89 | : (local) ( offset -- a ) 90 | frp @ swap - 91 | ; 92 | 93 | \ Set up a stack frame with n cells (popped from the data stack) and m 94 | \ uninitialized cells. 95 | : /locals \ 2.2990 xn ... x0 n m -- 96 | dup >r cells frp +! frp @ 97 | ds>mem mem> r> + swap >mem frp ! 98 | ; 99 | 100 | : locals/ ( -- ) \ 2.2991 -- 101 | frp @ mem> negate cells + frp ! 102 | ; 103 | 104 | there swap - . .( instructions used by stack framing) cr 105 | 106 | fpclear 107 | -------------------------------------------------------------------------------- /forth/io_equs.f: -------------------------------------------------------------------------------- 1 | \ I/O equates 2 | 3 | \ write read 4 | 0 cells equ io'udata \ UART out UART in 5 | 1 cells equ io'rxbusy \ set the code address UART receive status 6 | 2 cells equ io'txbusy \ write to code RAM UART send status 7 | 8 | 4 cells equ io'isp \ ISP byte ISP status 9 | 5 cells equ io'gkey \ set gecko key flash read status 10 | 6 cells equ io'fcfg \ format:size 11 | 6 cells equ io'cycles \ raw cycle count 12 | 10 cells equ io'fnext \ trigger next 13 | 11 cells equ io'fread \ start new flash read flash read result 14 | 12 cells equ io'boot \ other status: okay, ISP 15 | 2 equ bootokay 16 | 17 | $10 cells equ io'lcmd \ write command byte 18 | $11 cells equ io'ldata \ write data byte 19 | $12 cells equ io'lend \ chip select high 20 | $13 cells equ io'lgram \ write data cell (6:6:6 GRAM) 21 | \ $14 cells equ io'lraw \ raw data to LCD pins 22 | $15 cells equ io'lwtime \ write cycle timing 23 | $16 cells equ io'lrtime \ read cycle timing 24 | $17 cells equ io'lreset \ reset pin control 25 | 26 | $18 cells equ io'leds \ LEDs switches 27 | 28 | -------------------------------------------------------------------------------- /forth/more.f: -------------------------------------------------------------------------------- 1 | \ Extra words that I don't really use 2 | 3 | : -rot swap >r swap r> ; 4 | 5 | : sm/rem \ d n -- rem quot \ 6.1.2214 6 | 2dup xor >r over >r abs >r dabs r> um/mod 7 | swap r> 0< if negate then 8 | swap r> 0< if negate then ; 9 | 10 | : fm/mod \ d n -- rem quot \ 6.1.1561 11 | dup >r 2dup xor >r dup >r abs >r dabs r> um/mod 12 | swap r> 0< if negate then 13 | swap r> 0< if negate over if r@ rot - swap 1- then then 14 | r> drop ; 15 | 16 | : (umin) over over- drop carry ; 17 | : umin (umin) if swap drop exit then drop ; 18 | : umax (umin) if drop exit then swap drop ; 19 | 20 | : roll \ 2.2980 xu..x0 u -- xu-1..x0 xu 21 | ?dup if 22 | 1+ frp @ ds>mem mem> 23 | 1- over cell - ( a u' 'xu ) 24 | dup @ >r ! 25 | mem>ds drop r> 26 | then 27 | ; 28 | 29 | hex 30 | \ Attempt to convert utf-8 code point 31 | : nextutf8 \ n a -- n' a' \ add to utf-8 xchar 32 | >r 6 lshift r> count \ expect 80..BF 33 | dup 0C0 and 80 <> -0D and throw \ n' a c 34 | 3F and swap >r + r> 35 | ; 36 | : isutf8 \ addr len -- xchar 37 | over c@ 0F0 < over 1 = and if \ plain ASCII 38 | drop c@ exit 39 | then 40 | over c@ 0E0 < over 2 = and if \ 2-byte utf-8 41 | drop count 1F and swap nextutf8 42 | drop exit 43 | then 44 | over c@ 0F0 < over 3 = and if \ 3-byte utf-8 45 | drop count 1F and swap nextutf8 nextutf8 46 | drop exit 47 | then 48 | -0D throw 49 | ; 50 | decimal 51 | -------------------------------------------------------------------------------- /forth/myfont.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/forth/myfont.bin -------------------------------------------------------------------------------- /forth/numout.f: -------------------------------------------------------------------------------- 1 | \ Numeric conversion and text I/O 2 | \ The buffer for numeric conversion is just below the tib. 3 | \ The output string grows downward in memory. 4 | 5 | there 6 | decimal 7 | variable hld \ 2.3000 -- c-addr 8 | 32 equ bl \ 2.3010 -- char 9 | 10 | frp0 equ numbuf \ buffer for numeric conversion 11 | 12 | : decimal 10 base ! ; 13 | : hex 16 base ! ; 14 | :noname count emit ; ( xt ) \ send string to output device 15 | : type literal times drop ; \ 2.3140 c-addr u -- 16 | : s>d dup 0< ; \ 2.3150 n -- d 17 | : space bl emit ; \ 2.3160 -- 18 | : spaces ['] space times ; \ 2.3170 n -- 19 | 20 | \ Numeric conversion. `d.r` uses frame stack protection to prevent overflow 21 | \ when the stacks have significant content. Since `d.r` ia typically at the 22 | \ end of a definition, its tail call doesn't increase the stack. 23 | 24 | : digit dup -10 + 0< -7 and \ 2.3180 n -- char 25 | + [char] 7 + ; 26 | : <# numbuf hld ! ; \ 2.3190 ud1 -- ud1 27 | : hold hld dup >r @ 1- dup r> ! c! ; \ 2.3200 char -- 28 | : _#_ um/mod swap digit hold ; \ ud base -- u/base 29 | : # dup base @ >r if \ 2.3210 ud1 -- ud2 30 | 0 r@ um/mod r> swap 31 | >r _#_ r> exit 32 | then r> _#_ 0 33 | ; 34 | : #s begin # 2dup or 0= until ; \ 2.3220 ud1 -- ud2 35 | : sign 0< if [char] - hold then ; \ 2.3230 n -- 36 | : #> 2drop hld @ numbuf over - ; \ 2.3240 ud -- c-addr u 37 | : s.r over - spaces type ; \ length width -- 38 | : d.r 3 stack( >r dup >r dabs \ 2.3250 d width -- 39 | <# #s r> sign #> r> s.r )stack ; 40 | : u.r 0 swap d.r ; \ 2.3260 u width -- 41 | : .r >r s>d r> d.r ; \ 2.3270 n width -- 42 | : d. 0 d.r space ; \ 2.3280 d -- 43 | : u. 0 d. ; \ 2.3290 u -- 44 | : ? @ [ ; \ 2.3310 a -- 45 | : . s>d d. ; \ 2.3300 n -- 46 | : <#> >r <# begin # next #s #> ; \ ud digits-1 47 | : h.2 1 [ ; 48 | : h.x base @ >r hex 0 swap <#> r> \ 2.3320 u n -- 49 | base ! type space ; 50 | 51 | there swap - . .( instructions used by numeric output) cr 52 | -------------------------------------------------------------------------------- /forth/redirect.f: -------------------------------------------------------------------------------- 1 | \ Now let's get some I/O set up. ScreenProfile points to a table of xts. 2 | 3 | there 4 | 5 | variable ScreenProfile \ 2.2100 -- addr 6 | : ExecScreen ( n -- ) 7 | 2 min 2* ScreenProfile @ + w@ execute 8 | ; 9 | : emit 0 ExecScreen ; \ 2.2110 x -- 10 | : cr 1 ExecScreen ; \ 2.2111 x -- 11 | : page 2 ExecScreen ; \ 2.2112 x -- 12 | 13 | \ stdout is the screen: 14 | 15 | : _emit begin io'txbusy io@ while noop repeat io'udata io! ; 16 | : _cr 13 _emit 10 _emit ; \ -- 17 | : esc[x 27 emit [char] [ emit emit ; 18 | : _page [char] 2 esc[x [char] J emit ; \ "\e[2J" for VT100/VT220 19 | 20 | here 21 | ' _emit w, 22 | ' _cr w, 23 | ' _page w, 24 | align equ stdout_table 25 | 26 | : con ( -- ) \ direct to console 27 | stdout_table ScreenProfile ! 28 | ; con 29 | 30 | \ I/O sometimes needs timing, so here it is. 31 | 32 | variable hicycles 33 | 34 | :noname ( -- ) 35 | hicycles @ 1 + 36 | hicycles ! 37 | ; resolves irqtick \ clock cycle counter overflow interrupt 38 | 39 | \ Read raw cycle count. Since io@ returns after the lower count is read, 40 | \ it will service iqrtick if it has rolled over. hicycles is safe to read. 41 | 42 | : rawcycles ( -- ud ) 43 | io'cycles io@ hicycles @ 44 | ; 45 | 46 | \ Assume 100 MHz clock 47 | 48 | : ms ( n -- ) 49 | 100000 um* rawcycles d+ \ cycle count to wait for 50 | begin 2dup rawcycles du< \ spin until time elapsed 51 | until 2drop 52 | ; 53 | 54 | there swap - .( ) . .( instructions used by I/O redirect) cr 55 | -------------------------------------------------------------------------------- /forth/tools.f: -------------------------------------------------------------------------------- 1 | 2 | applets [if] .( Applet bytes: { ) \ } 3 | paged applet paged [then] 4 | 5 | : .s \ 2.6290 ? -- ? 6 | _.s ." <-Top " cr 7 | ; 8 | 9 | : fdump ( f-addr len -- ) \ only useful if tkey is 0 10 | dup if 11 | over 5 h.x 0 swap 12 | for 13 | over 15 and 0= if cr over 5 h.x then 14 | fcount h.2 15 | next 16 | then 2drop 17 | ; 18 | 19 | \ Dump in cell and char format 20 | 21 | 16 equ DumpColumns 22 | 23 | : udump ( c-addr u -- padding ) \ dump in cell format 24 | [ 1 cells 1- ] literal + cell/ \ round up to get all bytes 25 | [ DumpColumns cell/ ] literal 26 | dup>r min r> over - \ cells remainder 27 | [ cellbits 4 / 1+ ] literal * >r \ addr cells | padding 28 | for \ 1 or more cells 29 | @+ [ cellbits 4 / 1- ] literal h.x 30 | next drop 31 | r> 32 | ; 33 | 34 | : cdump ( caddr1 u1 -- caddr2 u2 ) \ dump in char format 35 | dup DumpColumns min 36 | for 37 | over c@ 38 | dup bl 192 within 0= if drop [char] . then 39 | emit 1 /string 40 | next 41 | ; 42 | 43 | : dump \ 2.6292 ( c-addr bytes -- ) 44 | >r [ -1 cells ] literal and r> \ cell-align the address 45 | begin dup while 46 | over 2 h.x space 47 | 2dup udump 1+ spaces 48 | cdump cr 49 | repeat 2drop 50 | ; 51 | 52 | applets [if] end-applet paged swap - . [then] 53 | .( } used by tools) cr 54 | 55 | -------------------------------------------------------------------------------- /forth/wiki/README.md: -------------------------------------------------------------------------------- 1 | # Wiki-like documentation files 2 | 3 | wiki files are text files used by the HTML documentation generator 4 | in `chad`. 5 | 6 | Forth source code normally has short reference markers in the format: 7 | 8 | 9 | When a REFERENCE is encountered, `chad` looks in this folder for its wiki entry. 10 | The lookup is brute-force, but on a modern computer it doesn't matter. 11 | 12 | -------------------------------------------------------------------------------- /forth/wiki/wikiasm.txt: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Assembler Reference 8 | 9 | 12 | 13 | 14 |

Assembler Reference

15 |
16 |

Execution: The simulator executes one instruction. 17 |
Compilation: One instruction is appended to code space. 18 |

19 |
20 |

Instruction Compile

21 |
22 | \ 23 | =1.5100: begin ( -- ) 24 | Assembler version of `begin`. 25 | =1.5110: again ( -- ) 26 | Assembler version of `again`. 27 | =1.5120: until ( -- ) 28 | Assembler version of `until`. 29 | =1.5130: if ( -- ) 30 | Assembler version of `if`. 31 | =1.5140: else ( -- ) 32 | Assembler version of `else`. 33 | =1.5150: then ( -- ) 34 | Assembler version of `then`. 35 | =1.5160: while ( -- ) 36 | Assembler version of `while`. 37 | =1.5170: repeat ( -- ) 38 | Assembler version of `repeat`. 39 | =1.5010: ;CODE ( 0 -- ) 40 | End a code definition. 41 | =1.5020: RET ( n1 -- n2 ) 42 | Set the ALU instruction `ret` field. Causes PC to be popped from return stack. 43 | =1.5021: >B ( n1 -- n2 ) 44 | Set the ALU instruction `>B` field. Causes B to be popped from data stack 45 | without including `T`: ( x y -- y' ) B=x. 46 | =1.6000: T ( n1 -- n2 ) 47 | No change in T. 48 | # 49 | _ 50 | H

Flow Control

51 | _ 52 | =1.6010: COP ( n1 -- n2 ) 53 | T = 0, place holder for coprocessor result. 54 | =1.6020: T0< ( n1 -- n2 ) 55 | All bits in T = MSB(T). 56 | =1.6030: C ( n1 -- n2 ) 57 | T = carry flag. 58 | =1.6040: T2/ ( n1 -- n2 ) 59 | T = signed T / 2. 60 | =1.6050: cT2/ ( n1 -- n2 ) 61 | T = carry-in T / 2. 62 | =1.6060: T2* ( n1 -- n2 ) 63 | T = T * 2 64 | =1.6070: T2*c ( n1 -- n2 ) 65 | T = T * 2 + carry 66 | =1.6080: N ( n1 -- n2 ) 67 | T = N 68 | =1.6090: A ( n1 -- n2 ) 69 | T = A 70 | =1.6091: B ( n1 -- n2 ) 71 | T = B 72 | =1.6000: T^N ( n1 -- n2 ) 73 | T = N ^ T 74 | =1.6110: ~T ( n1 -- n2 ) 75 | T = ~T 76 | =1.6120: T&N ( n1 -- n2 ) 77 | T = N & T 78 | =1.6130: >< ( n1 -- n2 ) 79 | T = ((T>>8) & 0xFF00FF) | ((T & 0xFF00FF)<<8) (swap even/odd bytes) 80 | =1.6140: ><16 ( n1 -- n2 ) 81 | T = ((T>>16) & 0xFFFF) | ((T & 0xFFFF) << 16) (swap 16-bit halves) 82 | =1.6150: T+N ( n1 -- n2 ) 83 | T = N + T 84 | =1.6160: T+Nc ( n1 -- n2 ) 85 | T = N + T + carry 86 | =1.6170: N-T ( n1 -- n2 ) 87 | T = N - T 88 | =1.6180: N-Tc ( n1 -- n2 ) 89 | T = N - T - carry 90 | =1.6190: T0= ( n1 -- n2 ) 91 | T = all '1's if T=0 else all '0's 92 | =1.6220: R ( n1 -- n2 ) 93 | T = R 94 | =1.6230: R-1 ( n1 -- n2 ) 95 | T = R - 1 96 | =1.6240: M ( n1 -- n2 ) 97 | T = M (see `[T]->M`) 98 | =1.6250: io ( n1 -- n2 ) 99 | T = io (see `io[T]->io`) 100 | =1.6260: status ( n1 -- n2 ) 101 | T = (rp<<8) | sp 102 | =1.7010: T->N ( n1 -- n2 ) 103 | N = T 104 | # 105 | _ 106 | H

ALU operations

107 | _ 108 | =1.7015: T->A ( n1 -- n2 ) 109 | A = T 110 | =1.7020: T->R ( n1 -- n2 ) 111 | R = T 112 | =1.7030: N->[T] ( n1 -- n2 ) 113 | Generate a memory write strobe. 114 | =1.7040: N->io[T] ( n1 -- n2 ) 115 | Generate an I/O write strobe. 116 | =1.7050: io[T]->io ( n1 -- n2 ) 117 | Generate an I/O read strobe. 118 | RA = T. 119 | =1.7060: [T]->M ( n1 -- n2 ) 120 | Generate a memory read strobe. 121 | RA = T. 122 | =1.7070: CO ( n1 -- n2 ) 123 | carry = carry out of adder or shifter 124 | =1.8010: r+ ( n1 -- n2 ) 125 | Push to return stack. 126 | # 127 | _ 128 | H

ALU strobes

129 | _ 130 | =1.8020: r- ( n1 -- n2 ) 131 | Pop from return stack. 132 | =1.8030: s+ ( n1 -- n2 ) 133 | Push to data stack. 134 | =1.8040: s- ( n1 -- n2 ) 135 | Pop from data stack. 136 | =1.9010: alu ( n -- 0 ) 137 | Compile `ALU` instruction 138 | # 139 | _ 140 | H

Stack pointer fields

141 | _ 142 | =1.9020: branch ( n -- 0 ) 143 | Compile `jump` instruction 144 | =1.9030: 0branch ( n -- 0 ) 145 | Compile `zjump` instruction 146 | =1.9040: scall ( n -- 0 ) 147 | Compile `call` instruction 148 | =1.9050: litx ( n -- 0 ) 149 | Compile `litx` instruction 150 | =1.9060: cop ( n -- 0 ) 151 | Compile coprocessor instruction. Not used. 152 | =1.9070: imm ( n -- 0 ) 153 | Compile ALU instruction 154 | = 155 | -------------------------------------------------------------------------------- /guisim/README.md: -------------------------------------------------------------------------------- 1 | # GUI simulation 2 | 3 | The `gui` is a simulated front panel based on a Freeglut DLL. 4 | It simulates a small LCD panel with ILI9341 or similar controller. 5 | There are also simulated pushbuttons. 6 | 7 | The project can be built with Visual Studio 2019 Community Edition. 8 | -------------------------------------------------------------------------------- /guisim/TFTsim.h: -------------------------------------------------------------------------------- 1 | #ifndef __TFTSIM_H__ 2 | #define __TFTSIM_H__ 3 | // Header file for TFTsim.c 4 | 5 | // Target BMP = 24-bit W x H if even type, H x W if odd type 6 | // format = bus width {8, 16, 9, 18, 8} and words/pixel: {2, 1, 2, 1, 3} 7 | // Type: 0=portrait, 1=landscape, 2=portrait, 3=landscape 8 | // width (W) must be a multiple of 4. 9 | int TFTLCDsetup(uint8_t* BMP, int type, int width, int height); 10 | 11 | // Send data to the controller. 12 | void TFTLCDdata(uint8_t format, uint32_t n); 13 | void TFTLCDcommand(uint8_t n); 14 | void TFTLCDend(void); 15 | 16 | #define PACKED16 0 // Pixel format over data bus 17 | #define WHOLE16 1 18 | #define PACKED18 2 19 | #define WHOLE18 3 20 | #define SERIAL8 4 21 | 22 | #define reverseRGB /* define to reverse the RGB order for OpenGL */ 23 | 24 | #endif 25 | -------------------------------------------------------------------------------- /guisim/clean.bat: -------------------------------------------------------------------------------- 1 | rem Copy executable to the bin folder and delete the intermediate files 2 | copy .\Release\gui.exe ..\bin 3 | rmdir Release /s /q 4 | -------------------------------------------------------------------------------- /guisim/freeglut.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/guisim/freeglut.dll -------------------------------------------------------------------------------- /guisim/freeglut.lib: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/guisim/freeglut.lib -------------------------------------------------------------------------------- /guisim/gui.h: -------------------------------------------------------------------------------- 1 | #ifndef __GUI_H__ 2 | #define __GUI_H__ 3 | // Header file for gui.c 4 | 5 | // A receiver for chars sent when a button is pressed or released. 6 | static void GUIbuttonHandler(char c); 7 | 8 | // LED status input is by calling a function: 9 | void LEDstripWrite(uint16_t sr); 10 | 11 | // Launch and run the gui window, user closes it. 12 | void GUIrun(void); 13 | 14 | // Load a test bitmap from a file "lcdimage.bmp". 15 | void GUILCDload(char* s); 16 | 17 | // LCDwrite uses a RS (cmd/data) select on bit 8 and data on bits 7:0 in: 18 | void GUILCDwrite(uint16_t n); 19 | 20 | #endif 21 | -------------------------------------------------------------------------------- /guisim/gui.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio Version 16 4 | VisualStudioVersion = 16.0.29519.181 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "gui", "gui.vcxproj", "{8DD914D9-841B-4577-90CF-CA1DEA92F55E}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Debug|x64.ActiveCfg = Debug|Win32 17 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Debug|x86.ActiveCfg = Debug|Win32 18 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Debug|x86.Build.0 = Debug|Win32 19 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Release|x64.ActiveCfg = Release|Win32 20 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Release|x86.ActiveCfg = Release|Win32 21 | {8DD914D9-841B-4577-90CF-CA1DEA92F55E}.Release|x86.Build.0 = Release|Win32 22 | EndGlobalSection 23 | GlobalSection(SolutionProperties) = preSolution 24 | HideSolutionNode = FALSE 25 | EndGlobalSection 26 | GlobalSection(ExtensibilityGlobals) = postSolution 27 | SolutionGuid = {828264BF-1F24-49CF-A875-3365A46F68A4} 28 | EndGlobalSection 29 | EndGlobal 30 | -------------------------------------------------------------------------------- /guisim/gui.vcxproj.filters: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;ipp;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Source Files 20 | 21 | 22 | Source Files 23 | 24 | 25 | Source Files 26 | 27 | 28 | Source Files 29 | 30 | 31 | Source Files 32 | 33 | 34 | Source Files 35 | 36 | 37 | Source Files 38 | 39 | 40 | Source Files 41 | 42 | 43 | Source Files 44 | 45 | 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | Source Files 70 | 71 | 72 | -------------------------------------------------------------------------------- /guisim/gui.vcxproj.user: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /guisim/include_glut/freeglut.h: -------------------------------------------------------------------------------- 1 | #ifndef __FREEGLUT_H__ 2 | #define __FREEGLUT_H__ 3 | 4 | /* 5 | * freeglut.h 6 | * 7 | * The freeglut library include file 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 12 | * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "freeglut_std.h" 18 | #include "freeglut_ext.h" 19 | 20 | /*** END OF FILE ***/ 21 | 22 | #endif /* __FREEGLUT_H__ */ 23 | -------------------------------------------------------------------------------- /guisim/include_glut/glut.h: -------------------------------------------------------------------------------- 1 | #ifndef __GLUT_H__ 2 | #define __GLUT_H__ 3 | 4 | /* 5 | * glut.h 6 | * 7 | * The freeglut library include file 8 | * 9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 10 | * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 11 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 12 | * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 13 | * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 14 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 15 | */ 16 | 17 | #include "freeglut_std.h" 18 | 19 | /*** END OF FILE ***/ 20 | 21 | #endif /* __GLUT_H__ */ 22 | -------------------------------------------------------------------------------- /guisim/main.cpp: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | extern "C" { 8 | #include "gui.h" 9 | #include "../src/config.h" 10 | #include "../src/chad.h" 11 | } 12 | 13 | using namespace std; 14 | 15 | static char command[LineBufferSize]; // a line buffer for Forth 16 | 17 | int main(int argc, char** argv) 18 | { 19 | std::thread thread1(GUIrun); // run the GUI separately 20 | 21 | // I was worried GLUT would interfere with keyboard input. 22 | // Miraculously, chad gets cooked-mode stdin like it wants. 23 | 24 | command[0] = '\0'; 25 | // concatenate everything on the command line to the line buffer 26 | for (int i = 1; i < argc; i++) { 27 | #ifdef MORESAFE 28 | strncat_s(command, LineBufferSize, argv[i], LineBufferSize); 29 | if (i != (argc - 1)) strncat_s(command, LineBufferSize, " ", 2); 30 | #else 31 | strncat(command, argv[i], LineBufferSize - strlen(command)); 32 | if (i != (argc - 1)) strncat(command, " ", 2); 33 | #endif 34 | } 35 | int ior = chad(command, LineBufferSize); 36 | exit(ior); // or tell glut to quit. How? 37 | // thread1.join(); // will hang until GUI quits 38 | 39 | return ior; 40 | } 41 | 42 | -------------------------------------------------------------------------------- /myapp/README.md: -------------------------------------------------------------------------------- 1 | # Sample Application 2 | 3 | This sample Forth app loads Forth code including a text interpreter (`quit` loop). 4 | 5 | It saves the output in several formats: 6 | 7 | - `.bin` is a binary image of the SPI flash with 16-byte boilerplate 8 | - `.txt` is the same image (sans boilerplate) in hex format for simulation 9 | - HTML documentation folder 10 | 11 | `chad` can boot and run the `.bin` file. 12 | If you program the data into a SPI flash, the synthesized MCU will boot and run it. 13 | 14 | If you look at the `.bin` file, you'll see several sections: 15 | 16 | - The 16-byte boilerplate: base sector, length, CRC32, and product ID 17 | - Boot code that initializes code and data memories 18 | - Dictionary headers 19 | - Text strings 20 | - Font bitmap data (in plaintext) 21 | 22 | -------------------------------------------------------------------------------- /myapp/html/doc.css: -------------------------------------------------------------------------------- 1 | 50 | 51 | .forth { 52 | font-weight: bold; 53 | font-family: monospace; 54 | } 55 | -------------------------------------------------------------------------------- /myapp/html/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | MyApp Reference 8 | 9 | 12 | 13 | 14 |

MyApp Reference

15 |
16 |

HTML documentation was generated by gendoc. 17 | See the source code of myapp.f. 18 | The generated files files are: 19 |

20 | 21 |
26 | 27 |

They are referenced by hyperlinked versions of each source file 28 | automatically generated by chad 29 | 30 |

41 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /myapp/myapp.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/myapp/myapp.bin -------------------------------------------------------------------------------- /myapp/myapp.f: -------------------------------------------------------------------------------- 1 | \ Application example 2 | 3 | \ To load: With your working directory here, type: 4 | \ ..\bin\chad include myapp.f (in Windows), or 5 | \ ../bin/chad include myapp.f (in Linux) 6 | \ If SPI flash is encrypted, for example, with `1 +bkey`, launch with: 7 | \ ..\bin\chad 1 +bkey boot myapp.bin 8 | 9 | \ To include the GUI stuff, 10 | \ ..\bin\gui include myapp.f 11 | 12 | \ Put text high enough in flash memory that it won't get clobbered by 13 | \ boot code and headers. Should be a multiple of 4096. 14 | 15 | $6000 forg \ strings in flash start here 16 | $8000 paged! \ applets start here 17 | 18 | 1 +bkey \ encrypt boot record if not zero 19 | 2 +tkey \ encrypt text if not zero 20 | 0 equ BASEBLOCK 21 | 0 constant applets \ use applets to reduce code RAM usage 22 | 23 | include ../forth/core.f 24 | include ../forth/coreext.f 25 | include ../forth/io_equs.f 26 | include ../forth/redirect.f 27 | include ../forth/frame.f 28 | include ../forth/numout.f 29 | include ../forth/flash.f 30 | include ../forth/compile.f 31 | include ../forth/api.f 32 | include ../forth/interpret.f 33 | include ../forth/tools.f 34 | include ../forth/bignum.f 35 | \ include ../forth/ctea.f 36 | 37 | \ Test some locals 38 | module \ private scope starts here 39 | 0 cells local fooTest 40 | 1 cells local barTest 41 | : first ." the first local is " fooTest ? cr ; 42 | : second ." the second local is " barTest ? cr ; 43 | exportable \ and ends here, but private section is findable 44 | : testlocals ( bar foo -- ) 45 | 2 0 /locals 46 | first second 47 | locals/ 48 | ; 49 | end-module \ end the scope of the private section 50 | 51 | \ Error handling 52 | 53 | [defined] quit [if] 54 | :noname ( error -- ) ?dup if quit then 55 | ; resolves throw \ quit handles the errors 56 | [else] 57 | :noname ( error -- ) ?dup if [ $4000 cells ] literal io! then 58 | ; resolves throw \ iomap.c sends errors to the Chad interpreter 59 | [then] 60 | 61 | \ Hardware loads code and data RAMs from flash. Upon coming out of reset, 62 | \ both are initialized. The PC can launch from 0 (cold). 63 | 64 | [defined] quit [if] 65 | 66 | : myapp ( -- ) 67 | \ [ $14 cells ] literal dup io@ \ read gp_i 68 | \ swap io! \ write top gp_o 69 | ." May the Forth be with you." 70 | 0 quit 71 | ; 72 | 73 | ' myapp resolves coldboot 74 | .( Application instructions: ) there . cr 75 | 76 | \ You can now run the app with "cold" 77 | 78 | : hi ." 多么美丽的世界 " ; 79 | 80 | [then] 81 | 82 | \ Examples 83 | 84 | : fib ( n1 -- n2 ) 85 | dup 2 < if drop 1 exit then 86 | dup 1 - recurse 87 | swap 2 - recurse + 88 | ; 89 | 90 | \ Try 25 fib, then stats 91 | .( Total instructions: ) there . cr 92 | 93 | 0 api ! \ should be 0 at boot time 94 | 95 | \ Save to a flash memory image 96 | [defined] lit, [if] \ if there's code for it... 97 | $2000 forg make-heads \ build headers in flash 98 | $0000 forg make-boot \ create a boot record in flash 99 | 1 0. BASEBLOCK save-flash myapp.bin \ save to a 'chad' file you can boot 100 | 2 0. BASEBLOCK save-flash myapp.txt \ save in hex for flash memory model 101 | 0 0. BASEBLOCK save-flash myappraw.bin \ save without boilerplate 102 | [then] 103 | 104 | \ You can now run the app with "boot myapp.bin" or a Verilog simulator. 105 | 106 | \ Now let's generate a language standard 107 | only forth 108 | gendoc ../forth/wiki/wikiforth.txt html/forth.html 109 | previous 110 | gendoc ../forth/wiki/wikiroot.txt html/root.html 111 | asm +order 112 | gendoc ../forth/wiki/wikiasm.txt html/asm.html 113 | only forth 114 | 115 | \ 8 verbosity cold \ track stack max 116 | \ 0 there dasm \ dumps all code 117 | -------------------------------------------------------------------------------- /src/README.md: -------------------------------------------------------------------------------- 1 | # C source files 2 | 3 | Chad is a C99 console app. 4 | 5 | Pull all of the files in this folder into a C project to compile. 6 | No other files are needed. 7 | 8 | You might not need to include `coproc.c` because it's `#include`d 9 | by `chad.c` rather than compiled and linked separately. 10 | This turned out to be a cleaner way to resolve its dependencies. 11 | -------------------------------------------------------------------------------- /src/_coproc.c: -------------------------------------------------------------------------------- 1 | /* 2 | This file is meant to be included in chad.c using #include so as to 3 | keep it physically near the simulator code to make it cache-friendly 4 | and to take advantage of predefined constants. 5 | */ 6 | 7 | #ifndef coprocGo 8 | 9 | // bit 0: hardware multiplier exists, trig = SBBBBB1001x, read = xxxxxx0001x 10 | // bit 1: hardware divider exists, trig = xxxxxx1010x, read = xxxxxx0010x 11 | // bit 2: hardware shifter exists, trig = xxxxSL1011x, read = xxxxxx0011x 12 | // bit 3: hardware LCD color exists, trig = xxxxMM1100x, read = xxxMMM0100x 13 | 14 | // In hardware, two different instructions operate the coprocessor. 15 | // 1. The COP class of instructions triggers a coprocessor operation. 16 | // The coprocessor gets 11 bits of immediate (sel) data. 17 | // 2. ALU operations read the result of a COP instruction. This COP data is 18 | // updated in real time, so it's useful for reading status. In simulation, 19 | // the status is always 0 (not busy) for simplicity. 20 | // Software uses coprocGo to start an operation. It can either poll the status 21 | // or just do a coprocRead if it knows sufficient cycles have elapsed. 22 | 23 | static uint32_t colorPlane(uint8_t gray6, uint8_t shift, uint32_t fg, uint32_t bg) { 24 | uint16_t fg6 = ((fg >> shift) & 0x3F) * gray6; 25 | uint16_t bg6 = ((bg >> shift) & 0x3F) * (gray6 ^ 0x3F); 26 | return ((fg6 + bg6) >> 6) << shift; 27 | } 28 | 29 | static uint32_t colorInterpolate(int gray4, uint32_t fg, uint32_t bg) { 30 | gray4 &= 15; // limit to 4-bit 31 | int gray6 = (gray4 << 2) | (gray4 >> 2); 32 | uint32_t r; 33 | r = colorPlane(gray6, 0, fg, bg); 34 | r += colorPlane(gray6, 6, fg, bg); 35 | r += colorPlane(gray6, 12, fg, bg); 36 | return r; 37 | } 38 | 39 | static int coprocSticky; 40 | static uint64_t cop_prod, cop_shift; 41 | static uint32_t cop_quot, cop_rem, cop_over; 42 | static uint32_t cop_fgcolor, cop_bgcolor, cop_monobits, cop_color; 43 | 44 | static uint32_t coprocRead(void) { 45 | uint32_t r = 0; // default return value 46 | switch (coprocSticky & 0x0F) { // get the result of the previous operation 47 | case 1: r = cop_over | COP_OPTIONS; break; // trigger: 48 | case 2: r = CELLMASK & (cop_prod >> CELLBITS); break; // 9 49 | case 3: r = CELLMASK & cop_prod; break; // 9 50 | case 4: r = cop_quot; break; // 10 51 | case 5: r = cop_rem; break; // 10 52 | case 6: r = CELLMASK & (cop_shift >> CELLBITS); break; // 11 53 | case 7: r = CELLMASK & cop_shift; break; // 11 54 | case 8: r = cop_color; break; // 12 55 | } 56 | return r; 57 | } 58 | 59 | static void coprocGo( 60 | int sel, // operation select 61 | uint32_t tos, // top of stack register 62 | uint32_t nos, // next on stack register 63 | uint32_t w) { // w register 64 | 65 | coprocSticky = sel; 66 | int mulcount = ((sel >> 5) & 0x1F) + 1; 67 | int mulsign = (sel >> 10) & 1; 68 | uint64_t ud, temp, p; 69 | uint32_t us; 70 | 71 | switch ((sel >> 1) & 0x0F) { // start a new operation 72 | #if (COP_OPTIONS & 1) 73 | case 9: 74 | p = (uint64_t)tos; 75 | for (int i = 0; i < mulcount; i++) { 76 | if (p & 1) { 77 | us = (uint32_t)(p >> CELLBITS); 78 | ud = (uint64_t)nos; 79 | temp = us; 80 | if (mulsign) { 81 | temp |= (uint64_t)(us & MSB) << 1; 82 | ud |= (uint64_t)(nos & MSB) << 1; 83 | } 84 | ud = (ud + temp) << (CELLBITS - 1); 85 | p = ud | ((p >> 1) & (CELLMASK>>1)); 86 | } 87 | else { 88 | temp = p & ((uint64_t)1 << (2 * CELLBITS - 1)); // MSB 89 | p >>= 1; 90 | if (mulsign) p += temp; 91 | } 92 | } 93 | cop_prod = p; 94 | break; 95 | #endif 96 | #if (COP_OPTIONS & 2) 97 | case 10: 98 | ud = ((uint64_t)tos << CELLBITS) | nos; 99 | temp = ud / w; 100 | if (temp >> CELLBITS) { // quotient doesn't fit in cell 101 | cop_quot = CELLMASK; 102 | cop_rem = CELLMASK; 103 | cop_over = 0x100; 104 | } 105 | else { 106 | cop_quot = temp & CELLMASK; 107 | cop_rem = ud % w; 108 | cop_over = 0; 109 | } 110 | break; 111 | #endif 112 | #if (COP_OPTIONS & 4) 113 | case 11: 114 | ud = ((uint64_t)tos << CELLBITS) | nos; 115 | if (sel & 0x80) { // 32-bit rotate right 116 | us = (uint32_t)ud; 117 | temp = ((ud << 32) | us) >> (w & 0x1F); 118 | cop_shift = (uint32_t)temp; 119 | } 120 | else if (sel & 0x20) 121 | cop_shift = ud << w; 122 | else if (sel & 0x40) 123 | cop_shift = (signed)ud >> w; 124 | else 125 | cop_shift = ud >> w; 126 | break; 127 | #endif 128 | #if (COP_OPTIONS & 8) 129 | case 12: // actions: cload, mload, gray, mono 130 | switch ((sel >> 5) & 3) { 131 | case 0: // cload 132 | cop_fgcolor = tos; 133 | cop_bgcolor = nos; 134 | break; 135 | case 1: // mload 136 | cop_monobits = tos; 137 | break; 138 | case 2: // mono 139 | cop_color = (cop_monobits & 1) ? cop_fgcolor : cop_bgcolor; 140 | cop_monobits >>= 1; 141 | break; 142 | case 3: // gray 143 | cop_color = colorInterpolate(tos, cop_fgcolor, cop_bgcolor); 144 | break; 145 | } 146 | break; 147 | #endif 148 | default: break; 149 | } 150 | } 151 | #endif 152 | -------------------------------------------------------------------------------- /src/chad.h: -------------------------------------------------------------------------------- 1 | //=============================================================================== 2 | // chad.h 3 | //=============================================================================== 4 | #ifndef __CHAD_H__ 5 | #define __CHAD_H__ 6 | #include 7 | #include "config.h" 8 | 9 | // The Forth QUIT loop and simulator 10 | // Returns a return code: 0 = BYE 11 | // line: a line of text to evaluate upon entry to chad. 12 | // maxlength: the maximum length of the line buffer. 13 | int chad(char * line, int maxlength); 14 | 15 | // Writing to memory is a function of spif simulator in iomap. 16 | void chadToCode(uint32_t addr, uint32_t x); 17 | void chadToData(uint32_t addr, uint32_t x); 18 | 19 | void chadError(int32_t error); // Report an error 20 | 21 | uint64_t chadCycles(void); // total number of processor cycles 22 | 23 | #endif // __CHAD_H__ 24 | -------------------------------------------------------------------------------- /src/config.h: -------------------------------------------------------------------------------- 1 | //=============================================================================== 2 | // config.h 3 | // Basic configuration for chad.c 4 | //=============================================================================== 5 | #ifndef __CONFIG_H__ 6 | #define __CONFIG_H__ 7 | #include 8 | 9 | #define SIM_FILENAME "output.txt" 10 | 11 | #define CELLBITS 24 /* Width of a cell in bits, 16 to 32 */ 12 | // Sizes of memories in cells, should be an exact power of 2 13 | #define CodeSize 4096 /* Code memory 16-bit words */ 14 | #define CodeCache 512 /* Size of cache region */ 15 | #define DataSize 2048 /* Data memory cells */ 16 | #define DataCache 256 /* Size of cache region */ 17 | #define StackAwidth 5 /* log2(Stack cells) */ 18 | #define MAXSP 15 /* Maximum allowed SP */ 19 | #define MAXRP 15 /* Maximum allowed RP */ 20 | #define IRQheadspace 4 /* Headspace reserved for interrupts */ 21 | #define CodeAlignment 1 /* Alignment for new definitions */ 22 | #define TrapVector 16 /* Jump address for the two traps */ 23 | #define ExceptionVector 18 /* Jump address for exceptions */ 24 | 25 | #define MoreInstrumentation /* Simulator has more instrumentation */ 26 | //#define HASFLOATS /* Dotted numbers are floating point */ 27 | 28 | #define LineBufferSize 128 /* Size of line buffer */ 29 | #define MaxLineLength 80 /* Max TIB size */ 30 | #define MaxKeywords 2000 /* Number of headers */ 31 | #define MaxNameSize 32 /* Number of chars in a name (less 1) */ 32 | #define MaxAnchorSize 40 /* Number of chars in an anchor string (-1) */ 33 | #define MaxFiles 16 /* Max open files */ 34 | #define MaxFilePaths 32 /* Max unique files */ 35 | #define MaxWordlists 20 /* Max number of wordlists */ 36 | 37 | #ifdef _MSC_VER /* Visual Studio wants "safe" functions. */ 38 | #define MORESAFE /* Compiler supports them (C11, C17, etc). */ 39 | #endif 40 | 41 | #define StackSize (1 << StackAwidth) 42 | 43 | #if ((CodeSize-1) & CodeSize) 44 | #error CodeSize must be an exact power of 2 45 | #endif 46 | #if ((DataSize-1) & DataSize) 47 | #error DataSize must be an exact power of 2 48 | #endif 49 | #if ((StackSize-1) & StackSize) 50 | #error StackSize must be an exact power of 2 51 | #endif 52 | 53 | #define COP_OPTIONS 15 /* Coprocessor options */ 54 | 55 | //Set these up in the project's build configuration 56 | //#define HAS_LCDMODULE /* Include LCD module in I/O map */ 57 | //#define HAS_LEDSTRIP /* Include LED strip in I/O map */ 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /src/flash.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // flash.h 3 | //============================================================================== 4 | #ifndef __FLASH_H__ 5 | #define __FLASH_H__ 6 | 7 | int LoadFlashMem(char *filename, uint32_t origin); 8 | int SaveFlashMem(char* filename, uint32_t pid, int format); 9 | int FlashBaseBlock(void); 10 | 11 | // Write byte to flash directly, used to build boot list 12 | void FlashMemStore(uint32_t addr, uint8_t c); 13 | 14 | // Set the CSN pin state and the SPI format. 15 | void FlashMemSPIformat(int n); 16 | 17 | // 8-bit transfer via SPI: Send byte to SPI flash and receive the result byte. 18 | int FlashMemSPI8(uint8_t cin); 19 | 20 | // Calculate next CRC32 value 21 | uint32_t crcbyte(uint8_t byte, uint32_t CRCin); 22 | 23 | // Flash memory size in bytes 24 | #define FlashMemorySize 0x200000 25 | 26 | // The SPI flash clock is the system clock divided by this: 27 | #define clockDivisor 2 28 | 29 | #define SYSMHZ 150 30 | 31 | // 4K erase delay in system clocks 32 | #define ERASE_DELAY (45000 * SYSMHZ) 33 | #define WRSR_DELAY (5000 * SYSMHZ) 34 | #define BYTE_DELAY (3 * SYSMHZ) 35 | #define BYTE0_DELAY (28 * SYSMHZ) 36 | 37 | #define BAD_CREATEFILE -198 38 | #define BAD_OPENFILE -199 39 | #define BAD_NOTBLANK -60 40 | #define BAD_PAGEFAULT -69 41 | #define BAD_NOTENABLED -71 42 | #define BAD_FLASHADDR -83 43 | 44 | #endif // __FLASH_H__ 45 | -------------------------------------------------------------------------------- /src/gecko.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | Bit-wise simulation of the gecko stream cypher. 7 | */ 8 | 9 | static uint8_t s[31]; // NFSR1 10 | static uint8_t b[90]; // NFSR2 11 | static uint8_t x, y, a; 12 | #define KEY_LENGTH 7 13 | 14 | static uint8_t* p = s; 15 | 16 | static void nybl(int bits) { 17 | int n = 0; 18 | for (int i = 0; i < bits; i++) // hex digit 19 | n = (n << 1) + *--p; 20 | printf("%X", n); 21 | } 22 | static void nybls(int digits) { 23 | for (int i = 0; i < digits; i++) 24 | nybl(4); 25 | } 26 | 27 | void GeckoState(void) { // dump internal state in hex format 28 | printf("s = "); p = &s[31]; nybl(3); nybls(7); 29 | printf(", b = "); p = &b[90]; nybl(2); nybls(22); 30 | printf("\n"); 31 | } 32 | 33 | static void logic(void) { 34 | x = s[0] ^ s[2] ^ s[5] ^ s[6] ^ s[15] ^ s[17] ^ s[18] ^ s[20] ^ s[25] // x is next s[30] 35 | ^ (s[8] & s[18]) ^ (s[8] & s[20]) ^ (s[12] & s[21]) ^ (s[14] & s[19]) ^ (s[17] & s[21]) ^ (s[20] & s[22]) 36 | ^ (s[4] & s[12] & s[22]) ^ (s[4] & s[19] & s[22]) ^ (s[7] & s[20] & s[21]) ^ (s[8] & s[18] & s[22]) 37 | ^ (s[8] & s[20] & s[22]) ^ (s[12] & s[19] & s[22]) ^ (s[20] & s[21] & s[22]) ^ (s[4] & s[7] & s[12] & s[21]) 38 | ^ (s[4] & s[7] & s[19] & s[21]) ^ (s[4] & s[12] & s[21] & s[22]) ^ (s[4] & s[19] & s[21] & s[22]) 39 | ^ (s[7] & s[8] & s[18] & s[21]) ^ (s[7] & s[8] & s[20] & s[21]) ^ (s[7] & s[12] & s[19] & s[21]) 40 | ^ (s[8] & s[18] & s[21] & s[22]) ^ (s[8] & s[20] & s[21] & s[22]) ^ (s[12] & s[19] & s[21] & s[22]); 41 | 42 | y = s[0] ^ b[0] ^ b[24] ^ b[49] ^ b[79] ^ b[84] ^ (b[3] & b[59]) ^ (b[10] & b[12]) // y is next b[89] 43 | ^ (b[15] & b[16]) ^ (b[25] & b[53]) ^ (b[35] & b[42]) ^ (b[55] & b[58]) ^ (b[60] & b[74]) 44 | ^ (b[20] & b[22] & b[23]) ^ (b[62] & b[68] & b[72]) ^ (b[77] & b[80] & b[81] & b[83]); 45 | 46 | a = b[7] ^ b[11] ^ b[30] ^ b[40] ^ b[45] ^ b[54] ^ b[71] 47 | ^ (b[4] & b[21]) ^ (b[9] & b[52]) ^ (b[18] & b[37]) ^ (b[44] & b[76]) 48 | ^ b[5] ^ (b[8] & b[82]) ^ (b[34] & b[67] & b[73]) ^ (b[2] & b[28] & b[41] & b[65]) 49 | ^ (b[13] & b[29] & b[50] & b[64] & b[75]) ^ (b[6] & b[14] & b[26] & b[32] & b[47] & b[61]) 50 | ^ (b[1] & b[19] & b[27] & b[43] & b[57] & b[66] & b[78]) 51 | ^ s[23] ^ (s[3] & s[16]) ^ (s[9] & s[13] & b[48]) ^ (s[1] & s[24] & b[38] & b[63]); 52 | } 53 | 54 | static void shift_s(uint8_t s30, uint8_t b89) { 55 | memmove(s, &s[1], 30); 56 | s[30] = s30; 57 | memmove(b, &b[1], 89); 58 | b[89] = b89; 59 | } 60 | 61 | uint8_t GeckoByte(void) { // next PRNG byte 62 | uint8_t r = 0; 63 | for (int i = 0; i < 8; i++) { 64 | logic(); 65 | shift_s(x, y); 66 | r = (r << 1) + a; 67 | } 68 | return r; 69 | } 70 | 71 | void GeckoLoad(uint64_t key) { // load the key 72 | for (int i = 0; i < 128; i++) { 73 | uint8_t k; 74 | if (i < (KEY_LENGTH*8)) 75 | k = (key >> i) & 1; 76 | else 77 | k = b[121 - KEY_LENGTH*8]; 78 | shift_s(k, s[0]); 79 | } 80 | for (int i = 0; i < 32; i++) { // diffuse the key 81 | logic(); 82 | shift_s(x ^ a, y ^ a); 83 | } 84 | } 85 | 86 | -------------------------------------------------------------------------------- /src/gecko.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // gecko.h 3 | //============================================================================== 4 | #ifndef __GECKO_H__ 5 | #define __GECKO_H__ 6 | #include 7 | 8 | void GeckoState(void); 9 | void GeckoLoad(uint64_t key); 10 | uint8_t GeckoByte(void); 11 | 12 | #endif // __GECKO_H__ 13 | -------------------------------------------------------------------------------- /src/iomap.h: -------------------------------------------------------------------------------- 1 | //============================================================================== 2 | // iomap.h 3 | //============================================================================== 4 | #ifndef __IOMAP_H__ 5 | #define __IOMAP_H__ 6 | 7 | uint32_t readIOmap (uint32_t addr); 8 | int writeIOmap (uint32_t addr, uint32_t x); 9 | void killHostIO(void); 10 | 11 | // Load memory spaces from the boot stream 12 | void FlashMemBoot(int startaddr); 13 | 14 | #define BAD_IOADDR -70 15 | #define BAD_HOSTAPI -76 16 | 17 | extern uint64_t ChadBootKey; 18 | 19 | // Function prototypes for specialzed peripherals 20 | 21 | #ifdef HAS_LCDMODULE 22 | #include "../guisim/TFTsim.h" 23 | #endif 24 | 25 | #ifdef HAS_LEDSTRIP 26 | void LEDstripWrite(uint16_t sr); 27 | #endif 28 | 29 | #endif // __IOMAP_H__ 30 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "config.h" 5 | #include "chad.h" 6 | 7 | static char command[LineBufferSize]; // a line buffer for Forth 8 | 9 | int main(int argc, char *argv[]) { 10 | command[0] = 0; 11 | // concatenate everything on the command line to the line buffer 12 | for (int i=1; i < argc; i++) { 13 | #ifdef MORESAFE 14 | strncat_s(command, LineBufferSize, argv[i], LineBufferSize); 15 | if (i != (argc - 1)) strncat_s(command, LineBufferSize, " ", 2); 16 | #else 17 | strncat(command, argv[i], LineBufferSize - strlen(command)); 18 | if (i != (argc - 1)) strncat(command, " ", 2); 19 | #endif 20 | } 21 | int ior = chad(command, LineBufferSize); 22 | return ior; 23 | } 24 | 25 | // If you poll for window messages, use this. Return true to quit chad. 26 | // Or, just comment it out so _kbhit is not needed. 27 | // int chadSpinFunction(void) { 28 | // return 0; 29 | // } 30 | -------------------------------------------------------------------------------- /utility/README.md: -------------------------------------------------------------------------------- 1 | # Utilities 2 | 3 | - `isp` an In-System-Programming over UART tool. 4 | - `term` is a simple terminal using the same RS232 stack. 5 | - `fonts` is a Unicode bitmap extraction tool for LCDs. 6 | 7 | To Do: 8 | 9 | Integrate `isp` into `term` to allow firmware updates without leaving the terminal. 10 | -------------------------------------------------------------------------------- /utility/fonts/make.f: -------------------------------------------------------------------------------- 1 | 2 | include fontcmp.f 3 | 4 | \ H6: 16-pel text field, 10-pel letters 5 | \ H5: 24-pel text field, 14-pel letters 6 | \ H4: 32-pel text field, 20-pel letters <-- default 7 | \ H3: 48-pel text field, 30-pel letters 8 | \ H2: 64-pel text field, 40-pel letters 9 | 10 | 0 constant revision 11 | 12 | revision 2 /FONTS 13 | 14 | cr .( ASCII in H4 size ) 15 | /msg HasASCII \ minimum set of glyphs 16 | \ MSGfile test.txt \ include glyphs for this text 17 | \ ^--- this hangs MakeFont. Need to debug. 18 | H4 MakeFont 19 | 0 maketable 20 | 21 | cr .( Numbers in H2 size) 22 | /msg HasNumeric 23 | H2 MakeFont 24 | 1 maketable 25 | 26 | cr fhere . .( bytes of data total) 27 | save ../../forth/myfont.bin 28 | 29 | cr .( Finished generating the fonts) 30 | 31 | -------------------------------------------------------------------------------- /utility/fonts/test.txt: -------------------------------------------------------------------------------- 1 | This file is not empty 2 | And this is the second line. 3 | : hi ." 多么美丽的世界 " ; 4 | : heb ."תהילה לאלוהים ושלום עלי אדמות" ; 5 | Note: Amazingly, utf-8 editors show right-to-left languages in reverse order of the actual binary. 6 | So, the utf-8 is parsed normally and characters are rendered as parsed moving left. 7 | -------------------------------------------------------------------------------- /utility/isp/readme.md: -------------------------------------------------------------------------------- 1 | # In System Programming 2 | 3 | ## Using a serial port 4 | 5 | `isp.c` programs the target's SPI flash using a UART. 6 | Serial communication uses a cross-platform library that has a GPL license. Thanks, Teunis! 7 | The library numbers ports starting from 0, so `COM4` would be `3`. 8 | 9 | `isp.c` works but isn't polished. It was tested with Code::Blocks on Windows. 10 | 11 | NOTE: It should be broken by a change in the `ping` packet and translation of outgoing 12 | 10h-13h chars. Needs to be fixed. 13 | 14 | `term.c` is a terminal emulator. It redirects stdin and stdout to the COM port. 15 | You're supposed to be able to use pipes for this, but Windows is funny about that. 16 | Running `term` in ConEmu provides a decent terminal. 17 | 18 | ## Command Line of isp.c 19 | 20 | isp filename port# \[baud] 21 | 22 | - filename is a file path without embedded spaces. 23 | - port# is the COM port number. 24 | - baud is an optional baud rate. Default = 1MBPS. 25 | 26 | The input file is the SPI flash data with a 16-byte preamble, created by chad's "save-flash". 27 | Multi-byte numbers are little-endian. 28 | 29 | - "chad", 4-byte file type identifier 30 | - BASEBLOCK, 1-byte first 64KB sector of user flash 31 | - KEY_ID, 1-byte keyID 32 | - PRODUCT_ID, 2-byte product ID 33 | - Length, 4-byte number of bytes (n) in the data 34 | - CRC32, 4-byte CRC of the data 35 | - Data, n-byte boot data to be placed at address (BASEBLOCK<<16) in SPI flash 36 | 37 | ### USB-UART chips 38 | 39 | - CH330N or CH340, max baud rate = 2M 40 | - MCP2200, max baud rate = 1M 41 | - CY7C65213A, max baud rate = 3M 42 | - CP2102N, max baud rate = 3M 43 | - FT230X, max baud rate = 3M 44 | - FT232H, max baud rate = 12M 45 | 46 | ## Command Line of term.c 47 | 48 | term port# \[baud] 49 | 50 | - port# is the COM port number. In Windows, subtract 1. 51 | - baud is an optional baud rate. Default = 3MBPS. 52 | 53 | `term` by itself lists the eligible port numbers. 54 | To compile an executable, include `term.c`, `rs232.c`, and `rs232.h`. 55 | 56 | -------------------------------------------------------------------------------- /utility/isp/rs232.h: -------------------------------------------------------------------------------- 1 | /* 2 | *************************************************************************** 3 | * 4 | * Author: Teunis van Beelen 5 | * 6 | * Copyright (C) 2005 - 2020 Teunis van Beelen 7 | * 8 | * Email: teuniz@protonmail.com 9 | * 10 | *************************************************************************** 11 | * 12 | * This program is free software: you can redistribute it and/or modify 13 | * it under the terms of the GNU General Public License as published by 14 | * the Free Software Foundation, either version 3 of the License. 15 | * 16 | * This program is distributed in the hope that it will be useful, 17 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 18 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 19 | * GNU General Public License for more details. 20 | * 21 | * You should have received a copy of the GNU General Public License 22 | * along with this program. If not, see . 23 | * 24 | *************************************************************************** 25 | */ 26 | 27 | /* Last revision: August 6, 2020 */ 28 | 29 | /* For more info and how to use this library, visit: http://www.teuniz.net/RS-232/ */ 30 | 31 | 32 | #ifndef rs232_INCLUDED 33 | #define rs232_INCLUDED 34 | 35 | #ifdef __cplusplus 36 | extern "C" { 37 | #endif 38 | 39 | #include 40 | #include 41 | 42 | 43 | 44 | #if defined(__linux__) || defined(__FreeBSD__) 45 | 46 | #include 47 | #include 48 | #include 49 | #include 50 | #include 51 | #include 52 | #include 53 | #include 54 | #include 55 | 56 | #else 57 | 58 | #include 59 | 60 | #endif 61 | 62 | int RS232_OpenComport(int, int, const char *, int); 63 | int RS232_PollComport(int, unsigned char *, int); 64 | int RS232_SendByte(int, unsigned char); 65 | int RS232_SendBuf(int, unsigned char *, int); 66 | void RS232_CloseComport(int); 67 | void RS232_cputs(int, const char *); 68 | int RS232_IsDCDEnabled(int); 69 | int RS232_IsRINGEnabled(int); 70 | int RS232_IsCTSEnabled(int); 71 | int RS232_IsDSREnabled(int); 72 | void RS232_enableDTR(int); 73 | void RS232_disableDTR(int); 74 | void RS232_enableRTS(int); 75 | void RS232_disableRTS(int); 76 | void RS232_flushRX(int); 77 | void RS232_flushTX(int); 78 | void RS232_flushRXTX(int); 79 | int RS232_GetPortnr(const char *); 80 | 81 | #ifdef __cplusplus 82 | } /* extern "C" */ 83 | #endif 84 | 85 | #endif 86 | 87 | 88 | -------------------------------------------------------------------------------- /utility/isp/term.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #ifdef _WIN32 4 | #include 5 | #else 6 | #include 7 | #endif 8 | #include "rs232.h" 9 | 10 | /* 11 | Terminal stdio <--> COMport utility, C99. 12 | 13 | Command line parameters are: 14 | [baud] 15 | port# is the COM port number. 16 | baud is an optional baud rate. 17 | 18 | Serial communication uses https://gitlab.com/Teuniz/RS-232/ for cross-platform 19 | abstraction. Ports are numbered for this. Numbering starts at 0, so COM4 is 3. 20 | */ 21 | 22 | #define DEFAULTBAUD 3000000L 23 | #define DEFAULTPORT 9 24 | #define MAXPORTS 31 25 | 26 | void ms(int msec) { // time delay 27 | #ifdef _WIN32 28 | Sleep(msec); 29 | #else 30 | usleep(msec * 1000); 31 | #endif 32 | } 33 | 34 | #ifdef __linux__ 35 | #include 36 | /** 37 | Linux (POSIX) implementation of _kbhit(). 38 | Morgan McGuire, morgan@cs.brown.edu 39 | */ 40 | #include 41 | #include 42 | #include 43 | #include 44 | 45 | int KbHit(void) { // _kbhit in Linux 46 | static const int STDIN = 0; 47 | static bool initialized = false; 48 | 49 | if (!initialized) { 50 | // Use termios to turn off line buffering 51 | termios term; 52 | tcgetattr(STDIN, &term); 53 | term.c_lflag &= ~ICANON; 54 | tcsetattr(STDIN, TCSANOW, &term); 55 | setbuf(stdin, NULL); 56 | initialized = true; 57 | } 58 | 59 | int bytesWaiting; 60 | ioctl(STDIN, FIONREAD, &bytesWaiting); 61 | return bytesWaiting; 62 | } 63 | #else 64 | #include 65 | int KbHit(void) { 66 | return _kbhit(); 67 | } 68 | #endif 69 | 70 | #define maxlen 80 71 | char txbuf[128]; 72 | unsigned char rxbuf[128]; 73 | int portnum = DEFAULTPORT; 74 | 75 | void CloseCom(void) { 76 | ms(30); 77 | RS232_CloseComport(portnum); 78 | } 79 | 80 | int main(int argc, char *argv[]) 81 | { 82 | int baudrate = DEFAULTBAUD; 83 | if (argc < 2) { 84 | printf("Usage: 'term [baud]'\n"); 85 | printf("Possible port#:"); 86 | for (int i = 0; i < MAXPORTS; i++) { 87 | if (RS232_OpenComport(i, baudrate, "8N1", 0) == 0) { 88 | RS232_CloseComport(i); 89 | printf(" %d", i); 90 | } 91 | } 92 | return 1; 93 | } 94 | if (argc > 1) { 95 | char* p = argv[1]; 96 | portnum = 0; 97 | char c; 98 | while ((c = *p++)) portnum = portnum * 10 + (c - '0'); 99 | } 100 | if (argc > 2) { 101 | char* p = argv[2]; 102 | baudrate = 0; 103 | char c; 104 | while ((c = *p++)) baudrate = baudrate * 10 + (c - '0'); 105 | } 106 | 107 | if (RS232_OpenComport(portnum, baudrate, "8N1", 0)) { 108 | printf("Can't open com port %d\n", portnum); 109 | return 3; 110 | } 111 | printf("Opened port %d at %d BPS, ^C to quit.\n", portnum, baudrate); 112 | atexit(CloseCom); 113 | 114 | while (1) { 115 | if (KbHit()) { 116 | if (fgets(txbuf, maxlen, stdin)) { 117 | size_t len = strlen(txbuf); 118 | RS232_SendBuf(portnum, (unsigned char *)txbuf, (int)len); 119 | } 120 | } 121 | ms(30); 122 | int rxlen = RS232_PollComport(portnum, rxbuf, 127); 123 | rxbuf[rxlen] = 0; 124 | printf("%s", rxbuf); 125 | } 126 | } 127 | 128 | -------------------------------------------------------------------------------- /verilog/README.md: -------------------------------------------------------------------------------- 1 | # Hardware design files 2 | 3 | - `/boards` is top level evaluation board projects. 4 | - `/rtl` is synthesizable code for `chad`. 5 | - `/testbench` is testbenches for the modules in `/rtl`. 6 | -------------------------------------------------------------------------------- /verilog/boards/Efinix/README.md: -------------------------------------------------------------------------------- 1 | # Test results 2 | 3 | I bought a Xyloni board from Efinix, through Digikey. 4 | It has a T8F81C2 chip on it, which is a chip scale package with very tiny balls. 5 | The design synthesized to 36 MHz on that chip. 6 | The Efinity tool uses XML as the description language for top level interconnect to 7 | the HDL core design rather than inferring from HDL. 8 | 9 | The Efinity (2020.2) programmer uses `libusb`, a cross-platform USB API, to control the board's 10 | FTDI chip. I needed to change the driver using `zadig`, which got its underlying Python 11 | to talk to the board. I programmed the bitstream into the board's SPI flash. 12 | 13 | But, then the FTDI chip would not enumerate as a serial port. 14 | I uninstalled the driver a couple of times and was able to get the COM ports back. 15 | Naturally, it broke the programmer. You can't have one driver for UART and libusb. 16 | 17 | The Efinity programmer doesn't have facility for adding user data to the programming file. 18 | No problem, I didn't need it. If I were to use Efinix FPGAs in production, I would not use 19 | their programmer. I would use a separate SPI flashing dongle such as FT232H cable or Dediprog SF600. 20 | 21 | Anyway, back to the COM port. Now I can receive serial data from the Xyloni board but not 22 | send to it. Or so it seems, since the same code works on other FPGA boards. 23 | Maybe I did something wrong, but the pain level turned me off to troubleshooting. 24 | 25 | So, the experiment didn't work. Efinix has come a very long way in a very short time. 26 | They will undoubtedly improve their tools. When their 16nm parts hit the supply chain, 27 | Efinix will be a serious player in the low end FPGA business. 28 | 29 | ## Plan B 30 | 31 | The T20 eval board is okay if a separate FTDI cable (or other COM adapter) provides the UART. 32 | 33 | The T13 and T20 in 0.8mm BGA (256-ball) are good low-cost FPGAs. 34 | The SPI flash can be programmed using FTDI SPI so that the configuration flash can be 35 | programmed without knowing anything about the FPGA. 36 | 37 | The MCU runs much faster in a T13/C3 than in a T8/C2: 75 MHz on a T13F256C3. 38 | The T13F256C4 can safely run at 80 MHz. 39 | It has 195 GPIOs available. 40 | 41 | 42 | -------------------------------------------------------------------------------- /verilog/boards/Efinix/demo_io.v: -------------------------------------------------------------------------------- 1 | // Peripherals for a Wishbone Bus 12/15/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This subsystem encapsulates the application's peripherals. 5 | // It connects to a Wishbone Bus controller such as an MCU or testbench. 6 | // Peripherals are put here to facilitate testing without an MCU. 7 | 8 | `default_nettype none 9 | module demo_io 10 | #( 11 | parameter WIDTH = 32, // Wishbone bus size 12 | parameter GPO_BITS = 16, // bits of general purpose output 13 | parameter GPI_BITS = 4 // bits of general purpose input 14 | )( 15 | input wire clk, 16 | input wire rst_n, 17 | // Wishbone Bob 18 | input wire [14:0] adr_i, // address 19 | output reg [WIDTH-1:0] dat_o, // data out 20 | input wire [WIDTH-1:0] dat_i, // data in 21 | input wire we_i, // 1 = write, 0 = read 22 | input wire stb_i, // strobe 23 | output reg ack_o, // acknowledge 24 | // GPIO 25 | output reg [GPO_BITS-1:0] gp_o, 26 | input wire [GPI_BITS-1:0] gp_i 27 | ); 28 | 29 | // Route stb_i and ack_o to the individual peripherals. 30 | 31 | reg [3:0] wbstb; 32 | always @* 33 | casez (adr_i[7:2]) 34 | 6'b000101: {wbstb, ack_o} <= {3'b000, stb_i, 1'b1}; 35 | default: {wbstb, ack_o} <= {4'b0000, 1'b1}; 36 | endcase 37 | 38 | always @* 39 | casez (adr_i[7:0]) 40 | default: dat_o <= gp_i; 41 | endcase 42 | 43 | // A simple peripheral for GPIO 44 | 45 | always @(posedge clk, negedge rst_n) begin 46 | if (!rst_n) begin 47 | gp_o <= 0; 48 | end else begin 49 | if (wbstb[0] & we_i) begin 50 | if (adr_i[0] == 0) 51 | gp_o <= dat_i[GPO_BITS-1:0]; // GP out 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | `default_nettype wire 58 | -------------------------------------------------------------------------------- /verilog/boards/Efinix/mcu_top.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 12/13/2020 BNE 2 | 3 | // Efinix version 4 | // The T20 part in 256BGA has a bitstream size of up to 10.4 64KB blocks. 5 | // The MCU is ported to the Xyloni board which has a T8F81. 6 | // Efinix uses an XML file managed by an Interface Editor to assign pins 7 | // and connections (such as tri-state buffers) to the design. 8 | 9 | `default_nettype none 10 | module mcu_top 11 | ( 12 | input wire clk, 13 | input wire rst_n, 14 | output wire [3:0] leds, 15 | input wire btn, 16 | // 4-wire connection to SPI flash chip 17 | output wire spi_sck, 18 | output wire spi_cs, 19 | input wire spi_di0, 20 | input wire spi_di1, 21 | output wire spi_do0, 22 | output wire spi_do1, 23 | output wire spi_oe0, 24 | output wire spi_oe1, 25 | // UART connection 26 | input wire uart_rxd, 27 | output wire uart_txd 28 | ); 29 | 30 | localparam BAUD_DIV = (34 / 2); // Divisor for 2MBPS UART 31 | localparam BASEBLOCK = 11; // for T20 32 | 33 | reg reset_n = 1'b0; 34 | reg rst_n1 = 1'b0; 35 | always @(posedge clk or negedge rst_n) 36 | if (!rst_n) {reset_n, rst_n1} <= 2'b00; 37 | else {reset_n, rst_n1} <= {rst_n1, 1'b1}; 38 | 39 | wire [3:0] qdo, qoe; 40 | wire [3:0] qdi = {2'b00, spi_di1, spi_di0}; 41 | assign {spi_do1, spi_do0} = qdo[1:0]; 42 | assign {spi_oe1, spi_oe0} = qoe[1:0]; 43 | wire [1:0] btns = {1'b0, btn}; 44 | 45 | // Wishbone Alice 46 | wire [14:0] adr_o; 47 | wire [31:0] dat_o, dat_i; 48 | wire we_o, stb_o, ack_i; 49 | 50 | // MCU 51 | mcu #(BASEBLOCK, BAUD_DIV, 24, 12, 10) small_mcu ( 52 | .clk (clk ), 53 | .rst_n (rst_n ), 54 | .sclk (spi_sck ), 55 | .cs_n (spi_cs ), 56 | .qdi (qdi ), 57 | .qdo (qdo ), 58 | .qoe (qoe ), 59 | .rxd (uart_rxd), 60 | .txd (uart_txd), 61 | .adr_o (adr_o ), 62 | .dat_o (dat_o ), 63 | .dat_i (dat_i ), 64 | .we_o (we_o ), 65 | .stb_o (stb_o ), 66 | .ack_i (ack_i ), 67 | .irqs (2'b00 ) 68 | ); 69 | 70 | demo_io #(32, 4, 2) simple_io ( 71 | .clk (clk ), 72 | .rst_n (rst_n ), 73 | .adr_i (adr_o ), 74 | .dat_o (dat_i ), 75 | .dat_i (dat_o ), 76 | .we_i (we_o ), 77 | .stb_i (stb_o ), 78 | .ack_o (ack_i ), 79 | .gp_o (leds ), 80 | .gp_i (btns ) 81 | ); 82 | 83 | endmodule 84 | `default_nettype wire 85 | -------------------------------------------------------------------------------- /verilog/boards/Efinix/xyloni_chad.sdc: -------------------------------------------------------------------------------- 1 | # PLL Constraints 2 | ################# 3 | # T13F256 C3 gives 77 MHz max. 4 | # The T20 eval board has a 50 MHz and 74.25 MHz oscillators. 5 | # We want to support a 26 MHz oscillator. 6 | # Lets target 60 MHz: 50 * (6/5) or 26 * (30/13) 7 | # or 72 MHz: or 50 * (13/9) 26 * (36/13) 8 | create_clock -period 16.66 [get_ports {clk}] 9 | # create_clock -period 13.88 [get_ports {clk}] 10 | -------------------------------------------------------------------------------- /verilog/boards/Efinix/xyloni_chad_io.isf: -------------------------------------------------------------------------------- 1 | # Efinity GPIO Pin Assignment 2 | # Version: 2020.2.299 3 | # Date: 2021-06-23 04:30 4 | # 5 | # Copyright (C) 2017 - 2020 Efinix Inc. All rights reserved. 6 | # 7 | # Device: T13F256 8 | # Package: 256-ball FBGA (final) 9 | # Project: xyloni_chad 10 | # Configuration mode: active (x1) 11 | # Timing Model: C3 (final) 12 | 13 | 14 | # Create instance 15 | design.create_output_gpio("leds",3,0) 16 | design.create_output_gpio("SD_CS") 17 | design.create_output_gpio("SD_DI") 18 | design.create_output_gpio("SD_DO") 19 | design.create_output_gpio("SD_SCLK") 20 | design.create_input_gpio("btn") 21 | design.create_pll_input_clock_gpio("gpio_inst18") 22 | design.create_input_gpio("my_pll_refclk") 23 | design.create_input_gpio("rst_n") 24 | design.create_output_gpio("spi_cs") 25 | design.create_inout_gpio("spi_data_0") 26 | design.create_inout_gpio("spi_data_1") 27 | design.create_output_gpio("spi_sck") 28 | design.create_input_gpio("uart_rxd") 29 | design.create_output_gpio("uart_txd") 30 | design.create_block("pll_inst1","PLL") 31 | 32 | # Set property, non-defaults 33 | design.set_property("SD_CS","OUT_PIN","system_spi_1_io_ss") 34 | design.set_property("SD_CS","OUT_CLK_PIN","io_systemClk") 35 | design.set_property("SD_SCLK","OUT_PIN","system_spi_1_io_sclk_write") 36 | design.set_property("SD_SCLK","OUT_CLK_PIN","io_systemClk") 37 | design.set_property("btn","PULL_OPTION","WEAK_PULLUP") 38 | design.set_property("gpio_inst18","IN_PIN","pll_clkin") 39 | design.set_property("rst_n","PULL_OPTION","WEAK_PULLUP") 40 | design.set_property("spi_cs","OUT_PIN","spi_ss") 41 | design.set_property("spi_cs","OUT_CLK_PIN","spi_ss") 42 | design.set_property("spi_data_0","IN_PIN","spi_di0") 43 | design.set_property("spi_data_0","OUT_PIN","spi_do0") 44 | design.set_property("spi_data_0","OUT_CLK_PIN","io_systemClk") 45 | design.set_property("spi_data_0","OE_PIN","spi_oe0") 46 | design.set_property("spi_data_0","OE_CLK_PIN","io_systemClk") 47 | design.set_property("spi_data_1","IN_PIN","spi_di1") 48 | design.set_property("spi_data_1","OUT_PIN","spi_do1") 49 | design.set_property("spi_data_1","OUT_CLK_PIN","io_systemClk") 50 | design.set_property("spi_data_1","OE_PIN","spi_oe1") 51 | design.set_property("spi_data_1","OE_CLK_PIN","io_systemClk") 52 | design.set_property("spi_sck","OUT_CLK_PIN","spi_spi_sck") 53 | design.set_property("uart_rxd","PULL_OPTION","WEAK_PULLUP") 54 | design.set_property("uart_txd","DRIVE_STRENGTH","4") 55 | design.set_property("pll_inst1","CLKOUT0_EN","1","PLL") 56 | design.set_property("pll_inst1","CLKOUT1_EN","0","PLL") 57 | design.set_property("pll_inst1","CLKOUT2_EN","0","PLL") 58 | design.set_property("pll_inst1","REFCLK_SOURCE","EXTERNAL","PLL") 59 | design.set_property("pll_inst1","CLKOUT0_DIV","30","PLL") 60 | design.set_property("pll_inst1","CLKOUT0_PHASE","0","PLL") 61 | design.set_property("pll_inst1","CLKOUT0_PIN","clk","PLL") 62 | design.set_property("pll_inst1","EXT_CLK","EXT_CLK0","PLL") 63 | design.set_property("pll_inst1","LOCKED_PIN","","PLL") 64 | design.set_property("pll_inst1","M","60","PLL") 65 | design.set_property("pll_inst1","N","1","PLL") 66 | design.set_property("pll_inst1","O","1","PLL") 67 | design.set_property("pll_inst1","REFCLK_FREQ","26.0","PLL") 68 | design.set_property("pll_inst1","RSTN_PIN","","PLL") 69 | design.set_property("pll_inst1","FEEDBACK_MODE","INTERNAL","PLL") 70 | 71 | # Set resource assignment 72 | design.assign_pkg_pin("leds[0]","H4") 73 | design.assign_pkg_pin("leds[1]","G3") 74 | design.assign_pkg_pin("leds[2]","G5") 75 | design.assign_pkg_pin("leds[3]","G2") 76 | design.assign_pkg_pin("SD_CS","H5") 77 | design.assign_pkg_pin("SD_DI","H1") 78 | design.assign_pkg_pin("SD_DO","L1") 79 | design.assign_pkg_pin("SD_SCLK","H3") 80 | design.assign_pkg_pin("btn","H2") 81 | design.assign_pkg_pin("gpio_inst18","C9") 82 | design.assign_pkg_pin("my_pll_refclk","D10") 83 | design.assign_pkg_pin("rst_n","G4") 84 | design.assign_pkg_pin("spi_cs","P3") 85 | design.assign_pkg_pin("spi_data_0","N3") 86 | design.assign_pkg_pin("spi_data_1","L4") 87 | design.assign_pkg_pin("spi_sck","M3") 88 | design.assign_pkg_pin("uart_rxd","F2") 89 | design.assign_pkg_pin("uart_txd","J5") 90 | design.assign_resource("pll_inst1","PLL_TR0","PLL") 91 | -------------------------------------------------------------------------------- /verilog/boards/LatticeECP5/mcu_top.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 10/18/2020 BNE 2 | 3 | // This synthesizes for a ECP5. 4 | 5 | `default_nettype none 6 | module mcu_top 7 | ( 8 | input wire clk_in, 9 | input wire rst_n, 10 | output wire [3:0] led, // test LEDs, red LD4 to LD7, 1=on 11 | input wire [3:0] sw, // slide switches 12 | input wire [3:0] btn, // pushbuttons 13 | output wire [2:0] RGB0, // color LEDs 14 | output wire [2:0] RGB1, 15 | output wire [2:0] RGB2, 16 | output wire [2:0] RGB3, 17 | // 6-wire connection to SPI flash chip 18 | output wire qspi_sck, 19 | output wire qspi_cs, 20 | inout wire [3:0] qspi_dq, 21 | // UART connection 22 | input wire uart_rxd, 23 | output wire uart_txd 24 | ); 25 | 26 | localparam BAUD_DIV = (96 / 3); // Divisor for 3MBPS UART 27 | localparam BASEBLOCK = 0; // External SPI flash 28 | 29 | wire clk = clk_in; 30 | wire locked = 1'b1; 31 | reg arst_n = 1'b0; 32 | reg rst_n1 = 1'b0; 33 | 34 | // clkgen clkgen_inst ( 35 | // .inclk0 ( clk_in ), 36 | // .c0 ( clk ), 37 | // .locked ( locked ) 38 | // ); 39 | 40 | always @(posedge clk) begin 41 | arst_n <= rst_n1; 42 | rst_n1 <= rst_n & locked; 43 | end 44 | 45 | assign led[0] = sw[0]; // sanity checks 46 | assign led[1] = uart_rxd ^ ~sw[1]; 47 | assign led[2] = uart_txd ^ ~sw[2]; 48 | assign led[3] = qspi_cs ^ ~sw[3]; 49 | 50 | wire [3:0] qdi = qspi_dq; // tri-state QSPI bus 51 | wire [3:0] qdo, oe; 52 | assign qspi_dq[0] = (oe[0]) ? qdo[0] : 1'bZ; 53 | assign qspi_dq[1] = (oe[1]) ? qdo[1] : 1'bZ; 54 | assign qspi_dq[2] = (oe[2]) ? qdo[2] : 1'bZ; 55 | assign qspi_dq[3] = (oe[3]) ? qdo[3] : 1'bZ; 56 | 57 | wire [11:0] gp_o; 58 | wire [3:0] gp_i = btn; 59 | assign {RGB0, RGB1, RGB2, RGB3} = gp_o; 60 | 61 | // MCU 62 | mcu #(BASEBLOCK, BAUD_DIV, 24, 13, 10, 12, 4) small_mcu ( 63 | .clk (clk ), 64 | .rst_n (arst_n ), 65 | .sclk (qspi_sck), 66 | .cs_n (qspi_cs ), 67 | .qdi (qdi ), 68 | .qdo (qdo ), 69 | .oe (oe ), 70 | .rxd (uart_rxd), 71 | .txd (uart_txd), 72 | .gp_o (gp_o ), 73 | .gp_i (gp_i ) 74 | ); 75 | 76 | endmodule 77 | -------------------------------------------------------------------------------- /verilog/boards/LatticeECP5/mcutop.sdc: -------------------------------------------------------------------------------- 1 | create_clock -period 83.333 -name clk_in [get_ports {clk_in}] 2 | derive_pll_clocks 3 | -------------------------------------------------------------------------------- /verilog/boards/LatticeXP2/Lattice_brevia2.lpf: -------------------------------------------------------------------------------- 1 | COMMERCIAL ; 2 | BLOCK RESETPATHS ; 3 | BLOCK ASYNCPATHS ; 4 | LOCATE COMP "clk_in" SITE "21" ; 5 | LOCATE COMP "rst_n" SITE "19" ; 6 | LOCATE COMP "uart_rx" SITE "110" ; 7 | LOCATE COMP "uart_tx" SITE "109" ; 8 | LOCATE COMP "led_0" SITE "46" ; 9 | LOCATE COMP "led_1" SITE "45" ; 10 | LOCATE COMP "led_2" SITE "44" ; 11 | LOCATE COMP "led_3" SITE "43" ; 12 | LOCATE COMP "led_4" SITE "40" ; 13 | LOCATE COMP "led_5" SITE "39" ; 14 | LOCATE COMP "led_6" SITE "38" ; 15 | LOCATE COMP "led_7" SITE "37" ; 16 | LOCATE COMP "spi_csn" SITE "11" ; 17 | LOCATE COMP "spi_miso" SITE "16" ; 18 | LOCATE COMP "spi_mosi" SITE "15" ; 19 | LOCATE COMP "spi_sclk" SITE "13" ; 20 | LOCATE COMP "wn" SITE "18" ; 21 | LOCATE COMP "holdn" SITE "17" ; 22 | LOCATE COMP "sw_0" SITE "58" ; 23 | LOCATE COMP "sw_1" SITE "57" ; 24 | LOCATE COMP "sw_2" SITE "56" ; 25 | LOCATE COMP "sw_3" SITE "55" ; 26 | LOCATE COMP "sw_4" SITE "54" ; 27 | LOCATE COMP "sw_5" SITE "53" ; 28 | LOCATE COMP "sw_6" SITE "52" ; 29 | LOCATE COMP "sw_7" SITE "50" ; 30 | IOBUF ALLPORTS IO_TYPE=LVCMOS33 ; 31 | IOBUF PORT "clk_in" IO_TYPE=LVCMOS33 PULLMODE=NONE ; 32 | #FREQUENCY NET "clk" 50.000000 MHz ; 33 | #INPUT_SETUP PORT "spi_miso" 5.000000 ns CLKNET "clk" ; 34 | #INPUT_SETUP PORT "uart_rx" 20.000000 ns CLKNET "clk" ; 35 | #CLOCK_TO_OUT PORT "uart_tx" 20.000000 ns CLKNET "clk" ; 36 | #CLOCK_TO_OUT PORT "spi_csn" 10.000000 ns CLKNET "clk" ; 37 | #CLOCK_TO_OUT PORT "spi_mosi" 10.000000 ns CLKNET "clk" ; 38 | #CLOCK_TO_OUT PORT "spi_sclk" 10.000000 ns CLKNET "clk" ; 39 | 40 | #LOCATE COMP "sram_addr_0" SITE "119" ; 41 | #LOCATE COMP "sram_addr_1" SITE "120" ; 42 | #LOCATE COMP "sram_addr_2" SITE "121" ; 43 | #LOCATE COMP "sram_addr_3" SITE "122" ; 44 | #LOCATE COMP "sram_addr_4" SITE "123" ; 45 | #LOCATE COMP "sram_addr_5" SITE "124" ; 46 | #LOCATE COMP "sram_addr_6" SITE "125" ; 47 | #LOCATE COMP "sram_addr_7" SITE "127" ; 48 | #LOCATE COMP "sram_addr_8" SITE "129" ; 49 | #LOCATE COMP "sram_addr_9" SITE "130" ; 50 | #LOCATE COMP "sram_addr_10" SITE "131" ; 51 | #LOCATE COMP "sram_addr_11" SITE "132" ; 52 | #LOCATE COMP "sram_addr_12" SITE "133" ; 53 | #LOCATE COMP "sram_addr_13" SITE "134" ; 54 | #LOCATE COMP "sram_addr_14" SITE "137" ; 55 | #LOCATE COMP "sram_addr_15" SITE "138" ; 56 | #LOCATE COMP "sram_addr_16" SITE "141" ; 57 | #LOCATE COMP "sram_cen" SITE "142" ; 58 | #LOCATE COMP "sram_data_0" SITE "1" ; 59 | #LOCATE COMP "sram_data_1" SITE "2" ; 60 | #LOCATE COMP "sram_data_2" SITE "5" ; 61 | #LOCATE COMP "sram_data_3" SITE "6" ; 62 | #LOCATE COMP "sram_data_4" SITE "7" ; 63 | #LOCATE COMP "sram_data_5" SITE "8" ; 64 | #LOCATE COMP "sram_data_6" SITE "9" ; 65 | #LOCATE COMP "sram_data_7" SITE "10" ; 66 | #LOCATE COMP "sram_oen" SITE "143" ; 67 | #LOCATE COMP "sram_wen" SITE "144" ; 68 | #INPUT_SETUP PORT "sram_data*" 5.000000 ns CLKNET "clk" ; 69 | #CLOCK_TO_OUT PORT "sram_addr*" 15.000000 ns CLKNET "clk" ; 70 | #CLOCK_TO_OUT PORT "sram_cen" 15.000000 ns CLKNET "clk" ; 71 | #CLOCK_TO_OUT PORT "sram_oen" 15.000000 ns CLKNET "clk" ; 72 | #CLOCK_TO_OUT PORT "sram_wen" 15.000000 ns CLKNET "clk" ; 73 | #CLOCK_TO_OUT PORT "sram_data*" 15.000000 ns CLKNET "clk" ; 74 | #DEFINE BUS BUS_SRAM 75 | # NET "sram_addr_c_0" 76 | # NET "sram_addr_c_1" 77 | # NET "sram_addr_c_2" 78 | # NET "sram_addr_c_3" 79 | # NET "sram_addr_c_4" 80 | # NET "sram_addr_c_5" 81 | # NET "sram_addr_c_6" 82 | # NET "sram_addr_c_7" 83 | # NET "sram_addr_c_8" 84 | # NET "sram_addr_c_9" 85 | # NET "sram_addr_c_10" 86 | # NET "sram_addr_c_11" 87 | # NET "sram_addr_c_12" 88 | # NET "sram_addr_c_13" 89 | # NET "sram_addr_c_14" 90 | # NET "sram_addr_c_15" 91 | # NET "sram_addr_c_16" 92 | # NET "sram_data_out_0" 93 | # NET "sram_data_out_1" 94 | # NET "sram_data_out_2" 95 | # NET "sram_data_out_3" 96 | # NET "sram_data_out_4" 97 | # NET "sram_data_out_5" 98 | # NET "sram_data_out_6" 99 | # NET "sram_data_out_7" 100 | # NET "sram_cen_int" 101 | # NET "sram_oen_int" 102 | # NET "sram_wen_int"; 103 | #DEFINE BUS BUS_SPI 104 | # NET "spi_sclk_c" 105 | # NET "spi_csn_c" 106 | # NET "spi_mosi_c"; 107 | #MAXSKEW BUS "BUS_SRAM" 3.000000 ns ; 108 | #MAXSKEW BUS "BUS_SPI" 3.000000 ns ; 109 | 110 | BLOCK JTAGPATHS ; 111 | FREQUENCY PORT "clk_in" 50.000000 MHz ; 112 | -------------------------------------------------------------------------------- /verilog/boards/LatticeXP2/README.md: -------------------------------------------------------------------------------- 1 | # Test Results 2 | 3 | This project is for a Brevia 2 board, with LFXP2-5 FPGA. 4 | 5 | ## Lattice XP2: OK 6 | 7 | No problems synthesizing the project and programming it into the FPGA's internal 8 | flash. It's much easier than with RAM-based FPGAs. 9 | 10 | It's clocked at 50 MHz, could be 75 MHz if the PLL is used. 11 | 12 | ## Gowin GW1N-4: Nope 13 | 14 | The Gowin LittleBee starter kit boards also have a 50 MHz oscillator. 15 | Same code should run on a DK-START-GW1N4 board. 16 | This board has a FT2232HL for JTAG. It doesn't connect the second port to the FPGA. 17 | Pins 38 and 39 can be soldered since U5 is TQFP. 18 | J9 pins 3 and 4 can be TX and RX pins for the UART. 19 | 20 | To avoid having to solder such tiny wires, a FTDI cable (TTL-232RG-VSW3V3-WE) 21 | can be plugged onto J9 header pins: 22 | 23 | | J9pin | PCB net | Wire Name | Wire Color | Pin | 24 | |-------|---------|-----------|------------|-----| 25 | | 1 | 3.3V | VCC | red | | 26 | | 2 | GND | GND | black | | 27 | | 3 | H_B_IO1 | RXD | orange | 130 | 28 | | 4 | H_B_IO2 | TXD | yellow | 129 | 29 | 30 | The UART is dead on arrival. Don't know why. 31 | -------------------------------------------------------------------------------- /verilog/boards/LatticeXP2/clkgen.v: -------------------------------------------------------------------------------- 1 | /* Verilog netlist generated by SCUBA Diamond (64-bit) 3.11.3.469 */ 2 | /* Module Version: 5.7 */ 3 | /* C:\lscc\diamond\3.11_x64\ispfpga\bin\nt64\scuba.exe -w -n clkgen -lang verilog -synth synplify -arch mg5a00 -type pll -fin 50 -phase_cntl STATIC -fclkop 100 -fclkop_tol 0.0 -fb_mode CLOCKTREE -noclkos -noclkok -norst -noclkok2 */ 4 | /* Fri Nov 20 23:54:03 2020 */ 5 | 6 | 7 | `timescale 1 ns / 1 ps 8 | module clkgen (CLK, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */; 9 | input wire CLK; 10 | output wire CLKOP; 11 | output wire LOCK; 12 | 13 | wire CLKOP_t; 14 | wire scuba_vlo; 15 | 16 | VLO scuba_vlo_inst (.Z(scuba_vlo)); 17 | 18 | // synopsys translate_off 19 | defparam PLLInst_0.CLKOK_BYPASS = "DISABLED" ; 20 | defparam PLLInst_0.CLKOS_BYPASS = "DISABLED" ; 21 | defparam PLLInst_0.CLKOP_BYPASS = "DISABLED" ; 22 | defparam PLLInst_0.PHASE_CNTL = "STATIC" ; 23 | defparam PLLInst_0.DUTY = 8 ; 24 | defparam PLLInst_0.PHASEADJ = "0.0" ; 25 | defparam PLLInst_0.CLKOK_DIV = 2 ; 26 | defparam PLLInst_0.CLKOP_DIV = 8 ; 27 | defparam PLLInst_0.CLKFB_DIV = 2 ; 28 | defparam PLLInst_0.CLKI_DIV = 1 ; 29 | // synopsys translate_on 30 | EPLLD1 PLLInst_0 (.CLKI(CLK), .CLKFB(CLKOP_t), .RST(scuba_vlo), .RSTK(scuba_vlo), 31 | .DPAMODE(scuba_vlo), .DRPAI3(scuba_vlo), .DRPAI2(scuba_vlo), .DRPAI1(scuba_vlo), 32 | .DRPAI0(scuba_vlo), .DFPAI3(scuba_vlo), .DFPAI2(scuba_vlo), .DFPAI1(scuba_vlo), 33 | .DFPAI0(scuba_vlo), .PWD(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), 34 | .CLKOK(), .LOCK(LOCK), .CLKINTFB()) 35 | /* synthesis CLKOK_BYPASS="DISABLED" */ 36 | /* synthesis CLKOS_BYPASS="DISABLED" */ 37 | /* synthesis FREQUENCY_PIN_CLKOP="100.000000" */ 38 | /* synthesis CLKOP_BYPASS="DISABLED" */ 39 | /* synthesis PHASE_CNTL="STATIC" */ 40 | /* synthesis DUTY="8" */ 41 | /* synthesis PHASEADJ="0.0" */ 42 | /* synthesis FREQUENCY_PIN_CLKI="50.000000" */ 43 | /* synthesis CLKOK_DIV="2" */ 44 | /* synthesis CLKOP_DIV="8" */ 45 | /* synthesis CLKFB_DIV="2" */ 46 | /* synthesis CLKI_DIV="1" */ 47 | /* synthesis FIN="50.000000" */; 48 | 49 | assign CLKOP = CLKOP_t; 50 | 51 | 52 | // exemplar begin 53 | // exemplar attribute PLLInst_0 CLKOK_BYPASS DISABLED 54 | // exemplar attribute PLLInst_0 CLKOS_BYPASS DISABLED 55 | // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 100.000000 56 | // exemplar attribute PLLInst_0 CLKOP_BYPASS DISABLED 57 | // exemplar attribute PLLInst_0 PHASE_CNTL STATIC 58 | // exemplar attribute PLLInst_0 DUTY 8 59 | // exemplar attribute PLLInst_0 PHASEADJ 0.0 60 | // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 50.000000 61 | // exemplar attribute PLLInst_0 CLKOK_DIV 2 62 | // exemplar attribute PLLInst_0 CLKOP_DIV 8 63 | // exemplar attribute PLLInst_0 CLKFB_DIV 2 64 | // exemplar attribute PLLInst_0 CLKI_DIV 1 65 | // exemplar attribute PLLInst_0 FIN 50.000000 66 | // exemplar end 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /verilog/boards/LatticeXP2/demo_io.v: -------------------------------------------------------------------------------- 1 | // Peripherals for a Wishbone Bus 12/15/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This subsystem encapsulates the application's peripherals. 5 | // It connects to a Wishbone Bus controller such as an MCU or testbench. 6 | // Peripherals are put here to facilitate testing without an MCU. 7 | 8 | `default_nettype none 9 | module demo_io 10 | #( 11 | parameter WIDTH = 32, // Wishbone bus size 12 | parameter GPO_BITS = 16, // bits of general purpose output 13 | parameter GPI_BITS = 4 // bits of general purpose input 14 | )( 15 | input wire clk, 16 | input wire rst_n, 17 | // Wishbone Bob 18 | input wire [14:0] adr_i, // address 19 | output reg [WIDTH-1:0] dat_o, // data out 20 | input wire [WIDTH-1:0] dat_i, // data in 21 | input wire we_i, // 1 = write, 0 = read 22 | input wire stb_i, // strobe 23 | output reg ack_o, // acknowledge 24 | // GPIO 25 | output reg [GPO_BITS-1:0] gp_o, 26 | input wire [GPI_BITS-1:0] gp_i 27 | ); 28 | 29 | // Route stb_i and ack_o to the individual peripherals. 30 | 31 | reg [3:0] wbstb; 32 | always @* 33 | casez (adr_i[7:2]) 34 | 6'b000101: {wbstb, ack_o} <= {3'b000, stb_i, 1'b1}; 35 | default: {wbstb, ack_o} <= {4'b0000, 1'b1}; 36 | endcase 37 | 38 | always @* 39 | casez (adr_i[7:0]) 40 | default: dat_o <= gp_i; 41 | endcase 42 | 43 | // A simple peripheral for GPIO 44 | 45 | always @(posedge clk, negedge rst_n) begin 46 | if (!rst_n) begin 47 | gp_o <= 0; 48 | end else begin 49 | if (wbstb[0] & we_i) begin 50 | if (adr_i[0] == 0) 51 | gp_o <= dat_i[GPO_BITS-1:0]; // GP out 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | `default_nettype wire 58 | -------------------------------------------------------------------------------- /verilog/boards/LatticeXP2/mcu_top.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 12/13/2020 BNE 2 | 3 | // This synthesizes for a Brevia 2 (LFXP2-5) with 50 MHz clock. 4 | 5 | module mcu_top 6 | ( 7 | input wire clk_in, 8 | input wire rst_n, 9 | output wire [7:0] led, // test LEDs 10 | input wire [7:0] sw, // test buttons 11 | // 6-wire connection to SPI flash chip 12 | output wire spi_sclk, 13 | output wire spi_csn, 14 | inout wire spi_mosi, // io0 15 | inout wire spi_miso, // io1 16 | inout wire wn, // io2 17 | inout wire holdn, // io3 18 | // UART connection 19 | input wire uart_rx, 20 | output wire uart_tx 21 | ); 22 | 23 | localparam BAUD_DIV = (50 / 3); // Divisor for 3MBPS UART 24 | localparam BASEBLOCK = 0; // External SPI flash 25 | 26 | wire clk = clk_in; 27 | wire locked = 1'b1; 28 | reg arst_n = 1'b0; 29 | reg rst_n1 = 1'b0; 30 | 31 | // clkgen clkgen_inst ( 32 | // .CLK ( clk_in ), 33 | // .CLKOP ( clk ), 34 | // .LOCK ( locked ) 35 | // ); 36 | 37 | always @(posedge clk) begin 38 | arst_n <= rst_n1; 39 | rst_n1 <= rst_n & locked; 40 | end 41 | 42 | wire [3:0] qdi, qdo, qoe; 43 | assign qdi = {holdn, wn, spi_miso, spi_mosi}; 44 | assign spi_mosi = (qoe[0]) ? qdo[0] : 1'bZ; 45 | assign spi_miso = (qoe[1]) ? qdo[1] : 1'bZ; 46 | assign wn = (qoe[2]) ? qdo[2] : 1'bZ; 47 | assign holdn = (qoe[3]) ? qdo[3] : 1'bZ; 48 | wire [7:0] ledn; 49 | assign led = ~ledn; 50 | 51 | // Wishbone Alice 52 | wire [14:0] adr_o; 53 | wire [31:0] dat_o, dat_i; 54 | wire we_o, stb_o, ack_i; 55 | 56 | // MCU 57 | mcu #(BASEBLOCK, BAUD_DIV, 24, 12, 10) small_mcu ( 58 | .clk (clk ), 59 | .rst_n (arst_n ), 60 | .sclk (spi_sclk), 61 | .cs_n (spi_csn ), 62 | .qdi (qdi ), 63 | .qdo (qdo ), 64 | .qoe (qoe ), 65 | .rxd (uart_rx ), 66 | .txd (uart_tx ), 67 | .adr_o (adr_o ), 68 | .dat_o (dat_o ), 69 | .dat_i (dat_i ), 70 | .we_o (we_o ), 71 | .stb_o (stb_o ), 72 | .ack_i (ack_i ), 73 | .irqs (2'b00 ) 74 | ); 75 | 76 | demo_io #(32, 8, 8) simple_io ( 77 | .clk (clk ), 78 | .rst_n (rst_n ), 79 | .adr_i (adr_o ), 80 | .dat_o (dat_i ), 81 | .dat_i (dat_o ), 82 | .we_i (we_o ), 83 | .stb_i (stb_o ), 84 | .ack_o (ack_i ), 85 | .gp_o (ledn ), 86 | .gp_i (sw ) 87 | ); 88 | 89 | endmodule 90 | -------------------------------------------------------------------------------- /verilog/boards/MAX10/clkgen.ppf: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /verilog/boards/MAX10/clkgen.qip: -------------------------------------------------------------------------------- 1 | set_global_assignment -name IP_TOOL_NAME "ALTPLL" 2 | set_global_assignment -name IP_TOOL_VERSION "20.1" 3 | set_global_assignment -name IP_GENERATED_DEVICE_FAMILY "{Cyclone IV E}" 4 | set_global_assignment -name VERILOG_FILE [file join $::quartus(qip_path) "clkgen.v"] 5 | set_global_assignment -name MISC_FILE [file join $::quartus(qip_path) "clkgen.ppf"] 6 | -------------------------------------------------------------------------------- /verilog/boards/MAX10/demo_io.v: -------------------------------------------------------------------------------- 1 | // Peripherals for a Wishbone Bus 12/15/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This subsystem encapsulates the application's peripherals. 5 | // It connects to a Wishbone Bus controller such as an MCU or testbench. 6 | // Peripherals are put here to facilitate testing without an MCU. 7 | 8 | `default_nettype none 9 | module demo_io 10 | #( 11 | parameter WIDTH = 32, // Wishbone bus size 12 | parameter GPO_BITS = 16, // bits of general purpose output 13 | parameter GPI_BITS = 4 // bits of general purpose input 14 | )( 15 | input wire clk, 16 | input wire rst_n, 17 | // Wishbone Bob 18 | input wire [14:0] adr_i, // address 19 | output reg [WIDTH-1:0] dat_o, // data out 20 | input wire [WIDTH-1:0] dat_i, // data in 21 | input wire we_i, // 1 = write, 0 = read 22 | input wire stb_i, // strobe 23 | output reg ack_o, // acknowledge 24 | // GPIO 25 | output reg [GPO_BITS-1:0] gp_o, 26 | input wire [GPI_BITS-1:0] gp_i 27 | ); 28 | 29 | // Route stb_i and ack_o to the individual peripherals. 30 | 31 | reg [3:0] wbstb; 32 | always @* 33 | casez (adr_i[7:2]) 34 | 6'b000101: {wbstb, ack_o} <= {3'b000, stb_i, 1'b1}; 35 | default: {wbstb, ack_o} <= {4'b0000, 1'b1}; 36 | endcase 37 | 38 | always @* 39 | casez (adr_i[7:0]) 40 | default: dat_o <= gp_i; 41 | endcase 42 | 43 | // A simple peripheral for GPIO 44 | 45 | always @(posedge clk, negedge rst_n) begin 46 | if (!rst_n) begin 47 | gp_o <= 0; 48 | end else begin 49 | if (wbstb[0] & we_i) begin 50 | if (adr_i[0] == 0) 51 | gp_o <= dat_i[GPO_BITS-1:0]; // GP out 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | `default_nettype wire 58 | -------------------------------------------------------------------------------- /verilog/boards/MAX10/mcu_top.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 10/18/2020 BNE 2 | 3 | // This synthesizes for a MAX10. It uses clkgen.v PLL IP. 4 | 5 | module mcu_top 6 | ( 7 | input wire clk_in, 8 | input wire rst_n, 9 | output wire [3:0] led, // test LEDs, red LD4 to LD7, 1=on 10 | input wire [3:0] sw, // slide switches 11 | input wire [3:0] btn, // pushbuttons 12 | output wire [2:0] RGB0, // color LEDs 13 | output wire [2:0] RGB1, 14 | output wire [2:0] RGB2, 15 | output wire [2:0] RGB3, 16 | // 6-wire connection to SPI flash chip 17 | output wire qspi_sck, 18 | output wire qspi_cs, 19 | inout wire [3:0] qspi_dq, 20 | // UART connection 21 | input wire uart_rxd, 22 | output wire uart_txd 23 | ); 24 | 25 | localparam BAUD_DIV = (96 / 3); // Divisor for 3MBPS UART 26 | localparam BASEBLOCK = 0; // External SPI flash 27 | 28 | wire clk, locked; 29 | reg arst_n = 1'b0; 30 | reg rst_n1 = 1'b0; 31 | 32 | clkgen clkgen_inst ( 33 | .inclk0 ( clk_in ), 34 | .c0 ( clk ), 35 | .locked ( locked ) 36 | ); 37 | 38 | always @(posedge clk) begin 39 | arst_n <= rst_n1; 40 | rst_n1 <= rst_n & locked; 41 | end 42 | 43 | assign led[0] = sw[0]; // sanity checks 44 | assign led[1] = uart_rxd ^ ~sw[1]; 45 | assign led[2] = uart_txd ^ ~sw[2]; 46 | assign led[3] = qspi_cs ^ ~sw[3]; 47 | 48 | wire [3:0] qdi = qspi_dq; // tri-state QSPI bus 49 | wire [3:0] qdo, qoe; 50 | assign qspi_dq[0] = (qoe[0]) ? qdo[0] : 1'bZ; 51 | assign qspi_dq[1] = (qoe[1]) ? qdo[1] : 1'bZ; 52 | assign qspi_dq[2] = (qoe[2]) ? qdo[2] : 1'bZ; 53 | assign qspi_dq[3] = (qoe[3]) ? qdo[3] : 1'bZ; 54 | 55 | wire [11:0] gp_o; 56 | wire [3:0] gp_i = btn; 57 | assign {RGB0, RGB1, RGB2, RGB3} = gp_o; 58 | 59 | // Wishbone Alice 60 | wire [14:0] adr_o; 61 | wire [31:0] dat_o, dat_i; 62 | wire we_o, stb_o, ack_i; 63 | 64 | // MCU 65 | mcu #(BASEBLOCK, BAUD_DIV, 24, 13, 10) small_mcu ( 66 | .clk (clk ), 67 | .rst_n (arst_n ), 68 | .sclk (qspi_sck), 69 | .cs_n (qspi_cs ), 70 | .qdi (qdi ), 71 | .qdo (qdo ), 72 | .qoe (qoe ), 73 | .rxd (uart_rxd), 74 | .txd (uart_txd), 75 | .adr_o (adr_o ), 76 | .dat_o (dat_o ), 77 | .dat_i (dat_i ), 78 | .we_o (we_o ), 79 | .stb_o (stb_o ), 80 | .ack_i (ack_i ), 81 | .irqs (2'b00 ) 82 | ); 83 | 84 | demo_io #(32, 16, 4) simple_io ( 85 | .clk (clk ), 86 | .rst_n (rst_n ), 87 | .adr_i (adr_o ), 88 | .dat_o (dat_i ), 89 | .dat_i (dat_o ), 90 | .we_i (we_o ), 91 | .stb_i (stb_o ), 92 | .ack_o (ack_i ), 93 | .gp_o (gp_o ), 94 | .gp_i (gp_i ) 95 | ); 96 | 97 | endmodule 98 | -------------------------------------------------------------------------------- /verilog/boards/MAX10/mcutop.sdc: -------------------------------------------------------------------------------- 1 | create_clock -period 83.333 -name clk_in [get_ports {clk_in}] 2 | derive_pll_clocks 3 | -------------------------------------------------------------------------------- /verilog/boards/Xilinx/README.md: -------------------------------------------------------------------------------- 1 | # Chad on the Digilent Arty A7 board 2 | 3 | This project runs Forth on the A7-35T board, available for $129.00 from Digilent. 4 | You also need a Micro USB cable and a 12V (2.1mm/5.5mm barrel plug) power supply. 5 | 6 | Xilinx makes it easy to add user data to the input file. 7 | The `myapp` project generates `myappraw.bin`, which is the boot code and dictionary. 8 | The board's flash part is `s25fl128sxxxxxx0-spi-x1_x2_x4`. 9 | With the implementation open, the bitstream properties has additional options you can set 10 | such as the SCLK speed, SPI width, etc. You need to set those properties if you want 11 | a usable bitstream. For example, the default SPI clock is 3 MHz. 12 | 13 | Set your serial terminal to 3M baud, echo locally. 14 | Chad'e `term` utility works from the command line, leveraging the terminal's cooked mode. 15 | -------------------------------------------------------------------------------- /verilog/boards/Xilinx/demo_io.v: -------------------------------------------------------------------------------- 1 | // Peripherals for a Wishbone Bus, Arty A7 version 12/15/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This subsystem encapsulates the application's peripherals. 5 | // It connects to a Wishbone Bus controller such as an MCU or testbench. 6 | // Peripherals are put here to facilitate testing without an MCU. 7 | 8 | `default_nettype none 9 | module demo_io 10 | #( 11 | parameter WIDTH = 32, // Wishbone bus size 12 | parameter GPO_BITS = 16, // bits of general purpose output 13 | parameter GPI_BITS = 4 // bits of general purpose input 14 | )( 15 | input wire clk, 16 | input wire rst_n, 17 | // Wishbone Bob 18 | input wire [14:0] adr_i, // address 19 | output reg [WIDTH-1:0] dat_o, // data out 20 | input wire [WIDTH-1:0] dat_i, // data in 21 | input wire we_i, // 1 = write, 0 = read 22 | input wire stb_i, // strobe 23 | output reg ack_o, // acknowledge 24 | // LCD module with 8-bit bus and internal frame buffer 25 | input wire [7:0] lcd_di, // read data 26 | output wire [7:0] lcd_do, // write data 27 | output wire lcd_oe, // lcd_d output enable 28 | output wire lcd_rd, // RDX pin 29 | output wire lcd_wr, // WRX pin 30 | output wire lcd_rs, // D/CX pin 31 | output wire lcd_cs, // CSX pin 32 | output wire lcd_rst, // RESET pin, active low 33 | // GPIO 34 | output reg [GPO_BITS-1:0] gp_o, 35 | input wire [GPI_BITS-1:0] gp_i 36 | ); 37 | 38 | // Instantiate an LCD controller 39 | 40 | wire lcd_sel = (adr_i[14:3] == 2); // 10h to 17h 41 | wire lcd_stb = stb_i & lcd_sel; 42 | wire lcd_ack; 43 | wire [7:0] lcd_dat; 44 | 45 | lcdcon u1( 46 | .clk (clk ), 47 | .rst_n (rst_n ), 48 | .adr_i (adr_i[2:0] ), 49 | .dat_o (lcd_dat ), 50 | .dat_i (dat_i[17:0]), 51 | .we_i (we_i ), 52 | .stb_i (lcd_stb ), 53 | .ack_o (lcd_ack ), 54 | .lcd_di (lcd_di ), 55 | .lcd_do (lcd_do ), 56 | .lcd_oe (lcd_oe ), 57 | .lcd_rd (lcd_rd ), 58 | .lcd_wr (lcd_wr ), 59 | .lcd_rs (lcd_rs ), 60 | .lcd_cs (lcd_cs ), 61 | .lcd_rst (lcd_rst ) 62 | ); 63 | 64 | // A simple peripheral for LEDs and switches 65 | 66 | wire led_sel = (adr_i[14:0] == 24); // 18h 67 | wire led_stb = stb_i & led_sel; 68 | 69 | always @(posedge clk, negedge rst_n) begin 70 | if (!rst_n) begin 71 | gp_o <= 0; 72 | end else begin 73 | if (led_sel & we_i) begin 74 | gp_o <= dat_i[GPO_BITS-1:0]; // GP out 75 | end 76 | end 77 | end 78 | 79 | // Wishbone return signals 80 | // ack is '1' by default so that accessing unused I/O doesn't hang. 81 | 82 | always @* begin 83 | if (lcd_sel) ack_o = lcd_ack; 84 | else ack_o = 1'b1; 85 | end 86 | 87 | always @* begin 88 | if (lcd_sel) dat_o = lcd_dat; 89 | else dat_o = gp_i; 90 | end 91 | 92 | endmodule 93 | `default_nettype wire 94 | -------------------------------------------------------------------------------- /verilog/boards/Xilinx/mcu_arty.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 12/1/2020 BNE 2 | 3 | // This runs on a Digilent Arty-A7-35 board 4 | // FPGA p/n XC7A35T-1CSG324C 5 | 6 | // Arty-A7 shorting block factory settings: JP1 and JP2 are ON. 7 | // JP1 = boot mode: ON = SPIflash, OFF = JTAG. 8 | // JP2 = reset over USB: ON = connect FT2232H (BDBUS4) to FPGA reset. 9 | // JP2 causes the FPGA to be reset when the COM port is opened. 10 | 11 | // An Artix-7 35T bitstream is typically 17,536,096 bits, 21728Ch bytes. 12 | // The BASEBLOCK for user flash is 22h. 13 | // The Arty A7 has a S25FL128SAGMFI00 (16MB) flash, which is mostly 64K sectors. 14 | 15 | `default_nettype none 16 | module mcu_arty 17 | ( 18 | input wire clk_in, 19 | input wire rst_n, 20 | output wire [3:0] led, // test LEDs, green LD4 to LD7, 1=on 21 | input wire [3:0] sw, // slide switches 22 | input wire [3:0] btn, // pushbuttons 23 | output wire [2:0] RGB0, // color LEDs 24 | output wire [2:0] RGB1, 25 | output wire [2:0] RGB2, 26 | output wire [2:0] RGB3, 27 | // LCD module with 8-bit bus and internal frame buffer 28 | inout wire [7:0] lcd_d, // read data 29 | wire lcd_rd, // RDX pin 30 | wire lcd_wr, // WRX pin 31 | wire lcd_rs, // DCX pin 32 | wire lcd_cs, // CSX pin 33 | wire lcd_rst, // RESET pin, active low 34 | // 6-wire connection to SPI flash chip 35 | output wire qspi_sck, 36 | output wire qspi_cs, 37 | inout wire [3:0] qspi_dq, 38 | // UART connection 39 | input wire uart_rxd, 40 | output wire uart_txd 41 | ); 42 | 43 | localparam BAUD_DIV = (100 / 3); // Divisor for 3MBPS UART 44 | localparam BASEBLOCK = 34; // for Artix-7 35T 45 | 46 | // The STARTUPE2 primitive can, in theory, supply CCLK to the SPI flash so that 47 | // the qspi_sck pin is not needed. I couldn't make it work, but Arty supplies the pin. 48 | 49 | wire clk, locked; 50 | reg arst_n = 1'b0; 51 | reg rst_n1 = 1'b0; 52 | 53 | assign clk = clk_in; // No PLL, the oscillator input is 100 MHz 54 | assign locked = 1'b1; 55 | 56 | always @(posedge clk) begin // provide a synced reset at power-up 57 | arst_n <= rst_n1; 58 | rst_n1 <= rst_n & locked; 59 | end 60 | 61 | assign led[0] = sw[0]; // sanity checks 62 | assign led[1] = uart_rxd ^ ~sw[1]; 63 | assign led[2] = uart_txd ^ ~sw[2]; 64 | assign led[3] = qspi_cs ^ ~sw[3]; 65 | 66 | wire [3:0] qdi = qspi_dq; // tri-state QSPI bus 67 | wire [3:0] qdo, qoe; 68 | assign qspi_dq[0] = (qoe[0]) ? qdo[0] : 1'bZ; 69 | assign qspi_dq[1] = (qoe[1]) ? qdo[1] : 1'bZ; 70 | assign qspi_dq[2] = (qoe[2]) ? qdo[2] : 1'bZ; 71 | assign qspi_dq[3] = (qoe[3]) ? qdo[3] : 1'bZ; 72 | 73 | wire [11:0] gp_o; 74 | assign {RGB0, RGB1, RGB2, RGB3} = gp_o; 75 | 76 | wire [7:0] lcd_do; 77 | wire lcd_oe; 78 | assign lcd_d = (lcd_oe) ? lcd_do : 8'bZ; 79 | 80 | // Wishbone Alice 81 | wire [14:0] adr_o; 82 | wire [31:0] dat_o, dat_i; 83 | wire we_o, stb_o, ack_i; 84 | 85 | // MCU 86 | mcu #(BASEBLOCK, BAUD_DIV, 24, 13, 10) small_mcu ( 87 | .clk (clk ), 88 | .rst_n (arst_n ), 89 | .sclk (qspi_sck), 90 | .cs_n (qspi_cs ), 91 | .qdi (qdi ), 92 | .qdo (qdo ), 93 | .qoe (qoe ), 94 | .rxd (uart_rxd), 95 | .txd (uart_txd), 96 | .adr_o (adr_o ), 97 | .dat_o (dat_o ), 98 | .dat_i (dat_i ), 99 | .we_o (we_o ), 100 | .stb_o (stb_o ), 101 | .ack_i (ack_i ), 102 | .irqs (2'b00 ) 103 | ); 104 | 105 | demo_io #(32, 12, 4) simple_io ( 106 | .clk (clk ), 107 | .rst_n (rst_n ), 108 | .adr_i (adr_o ), 109 | .dat_o (dat_i ), 110 | .dat_i (dat_o ), 111 | .we_i (we_o ), 112 | .stb_i (stb_o ), 113 | .ack_o (ack_i ), 114 | .lcd_di (lcd_d ), 115 | .lcd_do (lcd_do ), 116 | .lcd_oe (lcd_oe ), 117 | .lcd_rd (lcd_rd ), 118 | .lcd_wr (lcd_wr ), 119 | .lcd_rs (lcd_rs ), 120 | .lcd_cs (lcd_cs ), 121 | .lcd_rst (lcd_rst ), 122 | .gp_o (gp_o ), 123 | .gp_i (btn ) 124 | ); 125 | 126 | endmodule 127 | `default_nettype wire 128 | -------------------------------------------------------------------------------- /verilog/boards/Xilinx/tcl.txt: -------------------------------------------------------------------------------- 1 | write_cfgmem -format mcs -size 16 -interface SPIx4 -loadbit {up 0x00000000 "C:/Users/User/mcu_arty/mcu_arty.runs/impl_2/mcu_arty.bit" } -loaddata {up 0x00220000 "D:/Apps/chad/artyA7/appraw.bin" } -force -file "C:/Users/User/mcu_arty/mcu_arty.runs/impl_2/demo2" 2 | 3 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/README.md: -------------------------------------------------------------------------------- 1 | # iCESugar-Pro 2 | 3 | The [iCESugar-Pro] (https://github.com/wuxx/icesugar-pro) is by 4 | [Muse Lab] (https://muselab-tech.aliexpress.com/). 5 | It's a SODIMM module with on-board Lattice FPGA 6 | (LFE5U-25), SDRAM, SPI flash, uSD slot, and iCELink USB interface. 7 | The USB-C is set up to drag-and-drop bitstreams. 8 | It also supports a UART. 9 | On-board 25 MHz oscillator, RGB LED, and voltage regulators round out the board. 10 | It's a nice way to prototype FPGA-based systems. 11 | `chad` can be controlled through the on-module USB CDC UART. 12 | 13 | The module itself costs $47 on Alibaba. 14 | An extra $13 buys a breakout board with SODIMM-200 socket and a couple of connectors. 15 | These connectors are: 16 | 17 | - Six 2x15 0.1" headers, not populated. 18 | - USB-C with iCELink and pogo pins. 19 | - HDMI connector. 20 | 21 | The breakout board does not have a part number or manufacturer ID on it, 22 | but it's from the [Colorlight i5] 23 | (https://github.com/wuxx/Colorlight-FPGA-Projects#ext-board) project. 24 | 25 | This project only needs the iCESugar-Pro v1.3 module. 26 | Once it's programmed, you can access Forth through a terminal. 27 | 28 | The flash is a Winbond W25Q256JV. It comes with the QE bit set by default. 29 | It's way oversized: 256 Mb is 32 MB, or a 25-bit address. 30 | The FPGA bitstream only needs 5.5 Mb for a bitstream, or 11 Mb for dual-boot. 31 | To accommodate dual-boot and software write protect of the bitstreams, 32 | BOOTBLOCK is 32 (address 200000h). 33 | A smaller, 32Mb (4 MB) flash could be substituted. 34 | 35 | The W25Q256JVEIM has a DigiKey price of $2.40 on a 4K reel. 36 | SPI NOR flash price scales with capacity at this size. 37 | 1Gb costs four times as much. 38 | The $2.40 price point brings 4-byte addressing into the real world, 39 | so flash controller code should account for it. 40 | 41 | The demo uses P2 on the Ext Board, whose schematic uses funky pin numbering 42 | for the dual row headers and has ball numbers that don't match the iCESugar-Pro. 43 | 44 | On P2, 5 input switches are on odd pins (5,7,9,11,13) and 5 outputs are on even pins 45 | (6,8,10,12,14). These pins correspond to SODIMM pins and FPGA balls as follows: 46 | 47 | | P2 pin | ExtNet | SODOMM pin | ProNet | FPGA pin | 48 | |--------|---------|------------|--------|----------| 49 | | 5 | PR20D | 49 | PT35B | B8 | 50 | | 7 | PR44D | 57 | PT27B | B7 | 51 | | 9 | PR35D | 61 | PT22B | B6 | 52 | | 11 | PR32B | 65 | PT15B | B5 | 53 | | 13 | PR47A | 69 | PT11B | B4 | 54 | | 6 | PR47C | 41 | PT29B | A8 | 55 | | 8 | PR2A | 51 | PT29A | A7 | 56 | | 10 | PR44B | 59 | PT18B | A6 | 57 | | 12 | PR32D | 63 | PT18A | A5 | 58 | | 14 | PR47D | 67 | PT6B | A4 | 59 | 60 | The Lattice Diamond project uses the files in the `verilog/rtl` folder and this folder. 61 | Use Synplicity Pro for the synthesis engine. 62 | The `.bit` file (already built) can be programmed into the board by drag-and-drop. 63 | You can see that it's programmed by opening a serial terminal at 1MBPS and 64 | pressing the reset button. A `[` will appear. 65 | 66 | At this point, the application flash is blank and needs to be loaded with Forth. 67 | Use the ISP utility in `/bin`. 68 | 69 | # USB-C 70 | 71 | The on-module USB-C is very convenient. It makes it very easy to load a bitstream. 72 | The UART emulation is a little slow. Even at 1 MBPS, sometimes iCELink can't keep up. 73 | You can get a buffer overflow with `words` or `dump`. 74 | It spits out an error message but it recovers okay. 75 | 76 | As a module for a real product, it's a little hobbled. 77 | Without the USB-C, JTAG is only accessible through a row of pads. 78 | You would want a better USB-UART bridge, but that new USB would need pogo pins if 79 | JTAG access is needed. 80 | That might be a feature. The on-board USB-C could be limited to loading bitstreams 81 | and not for user access. 82 | 83 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/clkgen.v: -------------------------------------------------------------------------------- 1 | /* Verilog netlist generated by SCUBA Diamond (64-bit) 3.11.3.469 */ 2 | /* Module Version: 5.7 */ 3 | /* C:\lscc\diamond\3.11_x64\ispfpga\bin\nt64\scuba.exe -w -n clkgen -lang verilog -synth synplify -bus_exp 7 -bb -arch sa5p00 -type pll -fin 25 -fclkop 100.00 -fclkop_tol 0.0 -phase_cntl STATIC -lock -fb_mode 1 -fdc C:/lscc/projects/mcu_icesugar/clockgen/clkgen/clkgen.fdc */ 4 | /* Fri Sep 03 13:09:13 2021 */ 5 | 6 | 7 | `timescale 1 ns / 1 ps 8 | module clkgen (CLKI, CLKOP, LOCK)/* synthesis NGD_DRC_MASK=1 */; 9 | input wire CLKI; 10 | output wire CLKOP; 11 | output wire LOCK; 12 | 13 | wire REFCLK; 14 | wire CLKOP_t; 15 | wire scuba_vhi; 16 | wire scuba_vlo; 17 | 18 | VHI scuba_vhi_inst (.Z(scuba_vhi)); 19 | 20 | VLO scuba_vlo_inst (.Z(scuba_vlo)); 21 | 22 | defparam PLLInst_0.PLLRST_ENA = "DISABLED" ; 23 | defparam PLLInst_0.INTFB_WAKE = "DISABLED" ; 24 | defparam PLLInst_0.STDBY_ENABLE = "DISABLED" ; 25 | defparam PLLInst_0.DPHASE_SOURCE = "DISABLED" ; 26 | defparam PLLInst_0.CLKOS3_FPHASE = 0 ; 27 | defparam PLLInst_0.CLKOS3_CPHASE = 0 ; 28 | defparam PLLInst_0.CLKOS2_FPHASE = 0 ; 29 | defparam PLLInst_0.CLKOS2_CPHASE = 0 ; 30 | defparam PLLInst_0.CLKOS_FPHASE = 0 ; 31 | defparam PLLInst_0.CLKOS_CPHASE = 0 ; 32 | defparam PLLInst_0.CLKOP_FPHASE = 0 ; 33 | defparam PLLInst_0.CLKOP_CPHASE = 9 ; 34 | defparam PLLInst_0.PLL_LOCK_MODE = 0 ; 35 | defparam PLLInst_0.CLKOS_TRIM_DELAY = 0 ; 36 | defparam PLLInst_0.CLKOS_TRIM_POL = "FALLING" ; 37 | defparam PLLInst_0.CLKOP_TRIM_DELAY = 0 ; 38 | defparam PLLInst_0.CLKOP_TRIM_POL = "FALLING" ; 39 | defparam PLLInst_0.OUTDIVIDER_MUXD = "DIVD" ; 40 | defparam PLLInst_0.CLKOS3_ENABLE = "DISABLED" ; 41 | defparam PLLInst_0.OUTDIVIDER_MUXC = "DIVC" ; 42 | defparam PLLInst_0.CLKOS2_ENABLE = "DISABLED" ; 43 | defparam PLLInst_0.OUTDIVIDER_MUXB = "DIVB" ; 44 | defparam PLLInst_0.CLKOS_ENABLE = "DISABLED" ; 45 | defparam PLLInst_0.OUTDIVIDER_MUXA = "DIVA" ; 46 | defparam PLLInst_0.CLKOP_ENABLE = "ENABLED" ; 47 | defparam PLLInst_0.CLKOS3_DIV = 1 ; 48 | defparam PLLInst_0.CLKOS2_DIV = 1 ; 49 | defparam PLLInst_0.CLKOS_DIV = 1 ; 50 | defparam PLLInst_0.CLKOP_DIV = 10 ; 51 | defparam PLLInst_0.CLKFB_DIV = 5 ; 52 | defparam PLLInst_0.CLKI_DIV = 2 ; 53 | defparam PLLInst_0.FEEDBK_PATH = "CLKOP" ; 54 | EHXPLLL PLLInst_0 (.CLKI(CLKI), .CLKFB(CLKOP_t), .PHASESEL1(scuba_vlo), 55 | .PHASESEL0(scuba_vlo), .PHASEDIR(scuba_vlo), .PHASESTEP(scuba_vlo), 56 | .PHASELOADREG(scuba_vlo), .STDBY(scuba_vlo), .PLLWAKESYNC(scuba_vlo), 57 | .RST(scuba_vlo), .ENCLKOP(scuba_vlo), .ENCLKOS(scuba_vlo), .ENCLKOS2(scuba_vlo), 58 | .ENCLKOS3(scuba_vlo), .CLKOP(CLKOP_t), .CLKOS(), .CLKOS2(), .CLKOS3(), 59 | .LOCK(LOCK), .INTLOCK(), .REFCLK(REFCLK), .CLKINTFB()) 60 | /* synthesis FREQUENCY_PIN_CLKOP="65.000000" */ 61 | /* synthesis FREQUENCY_PIN_CLKI="26.000000" */ 62 | /* synthesis ICP_CURRENT="6" */ 63 | /* synthesis LPF_RESISTOR="16" */; 64 | 65 | assign CLKOP = CLKOP_t; 66 | 67 | 68 | // exemplar begin 69 | // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKOP 65.000000 70 | // exemplar attribute PLLInst_0 FREQUENCY_PIN_CLKI 26.000000 71 | // exemplar attribute PLLInst_0 ICP_CURRENT 6 72 | // exemplar attribute PLLInst_0 LPF_RESISTOR 16 73 | // exemplar end 74 | 75 | endmodule 76 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/demo_io.v: -------------------------------------------------------------------------------- 1 | // Peripherals for a Wishbone Bus 12/15/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This subsystem encapsulates the application's peripherals. 5 | // It connects to a Wishbone Bus controller such as an MCU or testbench. 6 | // Peripherals are put here to facilitate testing without an MCU. 7 | 8 | `default_nettype none 9 | module demo_io 10 | #( 11 | parameter WIDTH = 32, // Wishbone bus size 12 | parameter GPO_BITS = 16, // bits of general purpose output 13 | parameter GPI_BITS = 4 // bits of general purpose input 14 | )( 15 | input wire clk, 16 | input wire rst_n, 17 | // Wishbone Bob 18 | input wire [14:0] adr_i, // address 19 | output reg [WIDTH-1:0] dat_o, // data out 20 | input wire [WIDTH-1:0] dat_i, // data in 21 | input wire we_i, // 1 = write, 0 = read 22 | input wire stb_i, // strobe 23 | output reg ack_o, // acknowledge 24 | // GPIO 25 | output reg [GPO_BITS-1:0] gp_o, 26 | input wire [GPI_BITS-1:0] gp_i 27 | ); 28 | 29 | // Route stb_i and ack_o to the individual peripherals. 30 | 31 | reg [3:0] wbstb; 32 | always @* 33 | casez (adr_i[7:2]) 34 | 6'b000101: {wbstb, ack_o} <= {3'b000, stb_i, 1'b1}; // 40 io! 35 | default: {wbstb, ack_o} <= {4'b0000, 1'b1}; 36 | endcase 37 | 38 | always @* 39 | casez (adr_i[7:0]) 40 | default: dat_o <= gp_i; 41 | endcase 42 | 43 | // A simple peripheral for GPIO 44 | 45 | always @(posedge clk, negedge rst_n) begin 46 | if (!rst_n) begin 47 | gp_o <= 0; 48 | end else begin 49 | if (wbstb[0] & we_i) begin 50 | if (adr_i[0] == 0) 51 | gp_o <= dat_i[GPO_BITS-1:0]; // GP out 52 | end 53 | end 54 | end 55 | 56 | endmodule 57 | `default_nettype wire 58 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/dummy.v: -------------------------------------------------------------------------------- 1 | // Dummy module for exercising I/Os for PCB debugging 2 | 3 | module mcu_top 4 | ( 5 | input wire clk_in, 6 | output wire [7:0] led, // test LEDs 7 | input wire [4:0] sw, // test buttons 8 | // 6-wire connection to SPI flash chip 9 | output wire spi_csn, 10 | inout wire spi_mosi, // io0 11 | inout wire spi_miso, // io1 12 | inout wire spi_fd2, // io2 13 | inout wire spi_fd3, // io3 14 | output wire spi_sclk, // copy of SCLK for simulation (see USRMCLK) 15 | // UART connection 16 | input wire uart_rx, 17 | output wire uart_tx 18 | ); 19 | 20 | // The FPGA starts with reset registers generating a clean reset, so rst_n 21 | // is not needed. Good thing, because it's not on the FPGA board. 22 | 23 | wire clk = clk_in; 24 | reg arst_n = 1'b0; 25 | reg rst_n1 = 1'b0; 26 | reg [23:0] count = 24'd0; 27 | 28 | always @(posedge clk) begin 29 | arst_n <= rst_n1; 30 | rst_n1 <= 1'b1; 31 | count <= count + 1'b1; 32 | end 33 | 34 | assign uart_tx = uart_rx; // loop back UART 35 | assign led[0] = ~uart_rx; 36 | assign led[1] = count[23]; 37 | assign led[2] = count[22]; 38 | assign led[7:3] = sw[4:0]; 39 | 40 | assign spi_csn = count[23]; 41 | assign spi_mosi = count[17]; 42 | assign spi_miso = count[18]; 43 | assign spi_fd2 = count[19]; 44 | assign spi_fd3 = count[20]; 45 | 46 | // The SPI flash is shared by bitstream and application. 47 | // MCLK is usually not a user mode pin, but the ECP5 has a workaround: USRMCLK 48 | // This kills JTAG programming of the flash so you would want direct SPI connection 49 | // to program the flash. 50 | 51 | // Apparently, USRMCLK is being optimized away by Synplicity 52 | 53 | wire sclk_int = count[16]; 54 | assign spi_sclk = sclk_int; 55 | 56 | USRMCLK u1 (.USRMCLKI(sclk_int), .USRMCLKTS(spi_csn)) /* synthesis syn_noprune=1 */; 57 | // ^--- can't be a constant 58 | 59 | endmodule 60 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/iCESugarDemo_impl1.bit: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/verilog/boards/iceSugar-Pro1.3/iCESugarDemo_impl1.bit -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/mcu_top.v: -------------------------------------------------------------------------------- 1 | // Wrapper for the MCU 9/2/2021 BNE 2 | 3 | // This synthesizes for a iCESugar-Pro (ECP5) SODIMM module. 4 | // Synplify Pro gives much better timing results than LSE. 5 | // It wants at least 14ns cycle time, so clk (from clk_in) is: 6 | // 25MHz --> 62.5 MHz 7 | // 26MHz --> 65 MHz 8 | 9 | // The iCELink chip crashes with a 3M BPS baud rate, so use 1M BPS instead. 10 | 11 | module mcu_top 12 | ( 13 | input wire clk_in, 14 | output wire [7:0] led, // test LEDs 15 | input wire [4:0] sw, // test buttons 16 | // 6-wire connection to SPI flash chip 17 | output wire spi_csn, 18 | inout wire spi_mosi, // io0 19 | inout wire spi_miso, // io1 20 | inout wire spi_fd2, // io2 21 | inout wire spi_fd3, // io3 22 | output wire spi_sclk, // copy of SCLK for simulation (see USRMCLK) 23 | // UART connection 24 | input wire uart_rx, 25 | output wire uart_tx 26 | ); 27 | 28 | localparam BAUD_DIV = (63 / 1); // Divisor for 1MBPS UART 29 | localparam BASEBLOCK = 32; // SPI flash application at 2MB addr 30 | 31 | wire rst_n = 1'b1; // no reset pin 32 | 33 | // The FPGA starts with reset registers generating a clean reset, so rst_n 34 | // is not needed. Good thing, because it's not on the FPGA board. 35 | 36 | wire clk; 37 | wire locked; 38 | reg arst_n = 1'b0; 39 | reg rst_n1 = 1'b0; 40 | 41 | clkgen clkgen_inst ( // PLL 42 | .CLKI ( clk_in ), // 25 MHz input 43 | .CLKOP ( clk ), 44 | .LOCK ( locked ) 45 | ); 46 | 47 | always @(posedge clk) begin 48 | arst_n <= rst_n1; 49 | rst_n1 <= rst_n & locked; 50 | end 51 | 52 | // The SPI flash is shared by bitstream and application. 53 | // MCLK is usually not a user mode pin, but the ECP5 has a workaround: USRMCLK 54 | // This kills JTAG programming of the flash so you would want direct SPI connection 55 | // to program the flash. 56 | 57 | // USRMCLK gets pruned by Synplicity (thereby losing MCLK) if you're not careful. 58 | 59 | wire sclk_int; 60 | assign spi_sclk = sclk_int; 61 | 62 | USRMCLK u1 (.USRMCLKI(sclk_int), .USRMCLKTS(spi_csn)) /* synthesis syn_noprune=1 */; 63 | // ^--- can't be a constant 64 | 65 | wire [3:0] qdi, qdo, qoe; 66 | assign qdi = {spi_fd3, spi_fd2, spi_miso, spi_mosi}; 67 | assign spi_mosi = (qoe[0]) ? qdo[0] : 1'bZ; 68 | assign spi_miso = (qoe[1]) ? qdo[1] : 1'bZ; 69 | assign spi_fd2 = (qoe[2]) ? qdo[2] : 1'bZ; 70 | assign spi_fd3 = (qoe[3]) ? qdo[3] : 1'bZ; 71 | 72 | // Wishbone Alice 73 | wire [14:0] adr_o; 74 | wire [31:0] dat_o, dat_i; 75 | wire we_o, stb_o, ack_i; 76 | 77 | // MCU 78 | mcu #(BASEBLOCK, BAUD_DIV, 24, 12, 11) 79 | small_mcu ( 80 | .clk (clk ), 81 | .rst_n (arst_n ), 82 | .sclk (sclk_int), 83 | .cs_n (spi_csn ), 84 | .qdi (qdi ), 85 | .qdo (qdo ), 86 | .qoe (qoe ), 87 | .rxd (uart_rx ), 88 | .txd (uart_tx ), 89 | .adr_o (adr_o ), 90 | .dat_o (dat_o ), 91 | .dat_i (dat_i ), 92 | .we_o (we_o ), 93 | .stb_o (stb_o ), 94 | .ack_i (ack_i ), 95 | .irqs (2'b00 ) 96 | ); 97 | 98 | demo_io #(32, 8, 5) 99 | simple_io ( 100 | .clk (clk ), 101 | .rst_n (arst_n ), 102 | .adr_i (adr_o ), 103 | .dat_o (dat_i ), 104 | .dat_i (dat_o ), 105 | .we_i (we_o ), 106 | .stb_i (stb_o ), 107 | .ack_o (ack_i ), 108 | .gp_o (led ), 109 | .gp_i (sw ) 110 | ); 111 | 112 | endmodule 113 | -------------------------------------------------------------------------------- /verilog/boards/iceSugar-Pro1.3/top.lpf: -------------------------------------------------------------------------------- 1 | # iCESugar-Pro v1.3 2 | # 256-pin BGA, LFE5U-25 with: 3 | 4 | # 25 MHz oscillator 5 | # 2-wire UART 6 | # RGB LED 7 | # QSPI flash 8 | 9 | # LSE barfs on this file, Synplify Pro thinks it's okay. 10 | 11 | COMMERCIAL; 12 | BLOCK RESETPATHS; 13 | BLOCK ASYNCPATHS; 14 | 15 | # All banks connect their VCCIO to 3.3V 16 | IOBUF ALLPORTS IO_TYPE=LVCMOS33; 17 | SYSCONFIG CONFIG_IOVOLTAGE=3.3 COMPRESS_CONFIG=ON MCCLK_FREQ=62 SLAVE_SPI_PORT=DISABLE MASTER_SPI_PORT=DISABLE SLAVE_PARALLEL_PORT=DISABLE; 18 | 19 | # The default PULLMODE mode is DOWN, which is the most important feature from 20 | # a PCB design standpoint. During bitstream load, pins are pulled low. 21 | # The pull-down is 30uA (min) sustaining low, requiring 150uA (max) to pull high. 22 | 23 | # The default drive level is 8mA. 3.3V options are 4, 8, 12, or 16 mA. 24 | # Autmotive device might not support 12 and 16 mA device setting. 25 | # The default slew rate is "slow" (SLEWRATE=SLOW). 26 | 27 | # 25 MHz oscillator 28 | LOCATE COMP "clk_in" SITE "P6"; 29 | FREQUENCY PORT "clk_in" 25 MHZ; 30 | 31 | # PLL multiplies 25 to 62.5 MHz 32 | FREQUENCY NET "clkgen_inst.clk" 62.5 MHZ; 33 | 34 | # UART 35 | LOCATE COMP "uart_rx" SITE "A9"; 36 | LOCATE COMP "uart_tx" SITE "B9"; 37 | IOBUF PORT "uart_rx" PULLMODE=UP; 38 | 39 | # LED 40 | LOCATE COMP "led_0" SITE "B11"; #R 41 | LOCATE COMP "led_1" SITE "A11"; #G 42 | LOCATE COMP "led_2" SITE "A12"; #B 43 | LOCATE COMP "led_3" SITE "A8"; #P2 pin 6 44 | LOCATE COMP "led_4" SITE "A7"; #P2 pin 8 45 | LOCATE COMP "led_5" SITE "A6"; #P2 pin 10 46 | LOCATE COMP "led_6" SITE "A5"; #P2 pin 12 47 | LOCATE COMP "led_7" SITE "A4"; #P2 pin 14 48 | 49 | # switches - none are on the module, use P2 pins on EXT board 50 | 51 | LOCATE COMP "sw_0" SITE "B8"; #P2 pin 5 52 | LOCATE COMP "sw_1" SITE "B7"; #P2 pin 7 53 | LOCATE COMP "sw_2" SITE "B6"; #P2 pin 9 54 | LOCATE COMP "sw_3" SITE "B5"; #P2 pin 11 55 | LOCATE COMP "sw_4" SITE "B4"; #P2 pin 13 56 | 57 | # QSPI flash: 16Mb bitstream, 16Mb (or more) application 58 | LOCATE COMP "spi_csn" SITE "N8"; 59 | LOCATE COMP "spi_sclk" SITE "H4"; #unused ball 60 | LOCATE COMP "spi_mosi" SITE "T8"; 61 | LOCATE COMP "spi_miso" SITE "T7"; 62 | LOCATE COMP "spi_fd2" SITE "M7"; 63 | LOCATE COMP "spi_fd3" SITE "N7"; 64 | # Lattice ECP5U I/O capacitance is 8pF max. 65 | # Winbond W25Q256JV I/O capacitance is 8pF max. 66 | # Allowing 4pF for the PCB trace is 20pF. 67 | # It takes 8ns to move a 20pF load 3.3V at 8mA. 68 | # Compare to a 20ns cycle time (10 hi, 10 lo) at 50 MHz. 69 | # Note: Don't count on I/O pins to be faster than 30 MHz. The I/O pads in ASIC 70 | # like 130nm or 180nm process aren't that fast. The Sky130 I/O pad is 33 MHz. 71 | IOBUF PORT "spi_csn" DRIVE=8; 72 | IOBUF PORT "spi_sclk" DRIVE=8; 73 | IOBUF PORT "spi_mosi" DRIVE=8; 74 | IOBUF PORT "spi_miso" DRIVE=8; 75 | # In single-rate and dual-rate mode, pull WPn and HOLDn high 76 | IOBUF PORT "spi_fd2" DRIVE=8 PULLMODE=UP; 77 | IOBUF PORT "spi_fd3" DRIVE=8 PULLMODE=UP; 78 | 79 | -------------------------------------------------------------------------------- /verilog/rtl/cdc.v: -------------------------------------------------------------------------------- 1 | // Clock domain crossing with glitch removal 11/6/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // This module is used to bring asynchronous signals into a clock domain. 5 | // It allows for metastable behavior in the first couple of flops, including 6 | // metastability that doesn't settle within one clock cycle on both. 7 | // The `a` signal can be up to CLK/6 before the glitch filter impacts it. 8 | 9 | `default_nettype none 10 | module cdc 11 | ( 12 | input wire clk, 13 | input wire a, 14 | output reg y // propagation delay: 3 to 4 beats 15 | ); 16 | 17 | // B[3] and B[2] are not trusted. B[1] and B[0] are used to trigger the glitch timer. 18 | // The glitch timer provides two beats to shift B[1] into the bit bucket. 19 | // B[3:2] could be built with metastable-hardened flops for even more reliability. 20 | 21 | reg [3:0] b; // multi-flop delay shift register 22 | reg [1:0] c; // one-hot-coded glitch timer 23 | 24 | always @(posedge clk) begin 25 | b <= {a, b[3:1]}; // a -> bbbb (right-shift) 26 | if (c) // filtering 27 | c <= {1'b0, c[1]}; // right-shift c 28 | else begin 29 | y <= b[1]; 30 | if (b[1] != b[0]) 31 | c <= 2'b11; // start glitch filter 32 | end 33 | end 34 | 35 | endmodule 36 | `default_nettype wire 37 | -------------------------------------------------------------------------------- /verilog/rtl/coproc.v: -------------------------------------------------------------------------------- 1 | // Coprocessor for Chad processor 12/2/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | `include "options.vh" 5 | 6 | module coproc 7 | #( 8 | parameter WIDTH = 16 9 | ) 10 | ( 11 | input wire clk, 12 | input wire arstn, 13 | input wire [10:0] sel, 14 | input wire go, 15 | output reg [WIDTH-1:0] y, 16 | input wire [WIDTH-1:0] a, // tos 17 | input wire [WIDTH-1:0] b, // nos 18 | input wire [WIDTH-1:0] c // w 19 | ); 20 | 21 | wire mbusy, dbusy, sbusy, gbusy; 22 | 23 | `ifdef OPTIONS_IMULT // SBBBBB1001x 24 | wire mtrig = go & (sel[4:1] == 4'h9); 25 | wire [2*WIDTH-1:0] mprod; 26 | imultf #(WIDTH) u0 ( // iterative fractional multiply 27 | .clk (clk), 28 | .arstn (arstn), 29 | .busy (mbusy), 30 | .go (mtrig), 31 | .sign (sel[10]), 32 | .bits (sel[9:5]), 33 | .a (a), 34 | .b (b), 35 | .p (mprod) 36 | ); 37 | `else 38 | wire [2*WIDTH-1:0] mprod = 0; 39 | assign mbusy = 0; 40 | `endif 41 | 42 | `ifdef OPTIONS_IDIV // xxxxxx1010x 43 | wire dtrig = go & (sel[4:1] == 4'hA); 44 | wire overflow; 45 | wire [WIDTH-1:0] quot, rem; 46 | idivu #(WIDTH) u1 ( // iterative divide 47 | .clk (clk), 48 | .arstn (arstn), 49 | .busy (dbusy), 50 | .go (dtrig), 51 | .dividend ({a,b}), 52 | .divisor (c), 53 | .quot (quot), 54 | .rem (rem), 55 | .overflow (overflow) 56 | ); 57 | `else 58 | localparam quot = 0; 59 | localparam rem = 0; 60 | localparam overflow = 0; 61 | assign dbusy = 0; 62 | `endif 63 | 64 | `ifdef OPTIONS_ISHIFT // xxxxSL1011x 65 | wire strig = go & (sel[4:1] == 4'hB); 66 | wire [2*WIDTH-1:0] shifter; 67 | ishift #(2*WIDTH) u2 ( // iterative shift 68 | .clk (clk), 69 | .arstn (arstn), 70 | .busy (sbusy), 71 | .go (strig), 72 | .fmt (sel[7:5]), 73 | .cnt (c[5:0]), 74 | .a ({a,b}), 75 | .y (shifter) 76 | ); 77 | `else 78 | wire [2*WIDTH-1:0] shifter = 0; 79 | assign sbusy = 0; 80 | `endif 81 | 82 | `ifdef OPTIONS_TINYGPU // xxxMMM1100x 83 | wire gtrig = go & (sel[4:1] == 4'hC); 84 | wire [WIDTH-1:0] color; 85 | gpu #(WIDTH) u3 ( // small TFT helper 86 | .clk (clk), 87 | .rst_n (arstn), 88 | .sel (sel[6:5]), 89 | .go (gtrig), 90 | .busy (gbusy), 91 | .y (color), 92 | .a (a), 93 | .b (b) 94 | ); 95 | `else 96 | localparam color = 0; 97 | assign gbusy = 0; 98 | `endif 99 | 100 | reg [3:0] sticky; 101 | wire [3:0] outsel = (go) ? sel[3:0] : sticky; 102 | wire [7:0] options = `OPTIONS_COP; 103 | 104 | always @(posedge clk or negedge arstn) 105 | if (!arstn) 106 | {y, sticky} <= 1'b0; 107 | else begin 108 | if (go) sticky <= sel[3:0]; 109 | case (outsel) 110 | 4'h0: y <= mbusy | dbusy | sbusy | gbusy; 111 | 4'h1: y <= {overflow, options}; 112 | 4'h2: y <= mprod[2*WIDTH-1:WIDTH]; 113 | 4'h3: y <= mprod[WIDTH-1:0]; 114 | 4'h4: y <= quot; 115 | 4'h5: y <= rem; 116 | 4'h6: y <= shifter[2*WIDTH-1:WIDTH]; 117 | 4'h7: y <= shifter[WIDTH-1:0]; 118 | 4'h8: y <= color; 119 | default: y <= 1'b0; 120 | endcase 121 | end 122 | 123 | endmodule 124 | -------------------------------------------------------------------------------- /verilog/rtl/crc32.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | // https://bues.ch/h/crcgen 4 | 5 | module crc32 ( 6 | input wire [31:0] crcIn, 7 | input wire [7:0] data, 8 | output wire [31:0] crcOut 9 | ); 10 | assign crcOut[0] = (crcIn[2] ^ crcIn[8] ^ data[2]); 11 | assign crcOut[1] = (crcIn[0] ^ crcIn[3] ^ crcIn[9] ^ data[0] ^ data[3]); 12 | assign crcOut[2] = (crcIn[0] ^ crcIn[1] ^ crcIn[4] ^ crcIn[10] ^ data[0] ^ data[1] ^ data[4]); 13 | assign crcOut[3] = (crcIn[1] ^ crcIn[2] ^ crcIn[5] ^ crcIn[11] ^ data[1] ^ data[2] ^ data[5]); 14 | assign crcOut[4] = (crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[6] ^ crcIn[12] ^ data[0] ^ data[2] ^ data[3] ^ data[6]); 15 | assign crcOut[5] = (crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[7] ^ crcIn[13] ^ data[1] ^ data[3] ^ data[4] ^ data[7]); 16 | assign crcOut[6] = (crcIn[4] ^ crcIn[5] ^ crcIn[14] ^ data[4] ^ data[5]); 17 | assign crcOut[7] = (crcIn[0] ^ crcIn[5] ^ crcIn[6] ^ crcIn[15] ^ data[0] ^ data[5] ^ data[6]); 18 | assign crcOut[8] = (crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ crcIn[16] ^ data[1] ^ data[6] ^ data[7]); 19 | assign crcOut[9] = (crcIn[7] ^ crcIn[17] ^ data[7]); 20 | assign crcOut[10] = (crcIn[2] ^ crcIn[18] ^ data[2]); 21 | assign crcOut[11] = (crcIn[3] ^ crcIn[19] ^ data[3]); 22 | assign crcOut[12] = (crcIn[0] ^ crcIn[4] ^ crcIn[20] ^ data[0] ^ data[4]); 23 | assign crcOut[13] = (crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[21] ^ data[0] ^ data[1] ^ data[5]); 24 | assign crcOut[14] = (crcIn[1] ^ crcIn[2] ^ crcIn[6] ^ crcIn[22] ^ data[1] ^ data[2] ^ data[6]); 25 | assign crcOut[15] = (crcIn[2] ^ crcIn[3] ^ crcIn[7] ^ crcIn[23] ^ data[2] ^ data[3] ^ data[7]); 26 | assign crcOut[16] = (crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[24] ^ data[0] ^ data[2] ^ data[3] ^ data[4]); 27 | assign crcOut[17] = (crcIn[0] ^ crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[25] ^ data[0] ^ data[1] ^ data[3] ^ data[4] ^ data[5]); 28 | assign crcOut[18] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ crcIn[26] ^ data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6]); 29 | assign crcOut[19] = (crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ crcIn[27] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6] ^ data[7]); 30 | assign crcOut[20] = (crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[28] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 31 | assign crcOut[21] = (crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ crcIn[29] ^ data[2] ^ data[4] ^ data[5] ^ data[7]); 32 | assign crcOut[22] = (crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[30] ^ data[2] ^ data[3] ^ data[5] ^ data[6]); 33 | assign crcOut[23] = (crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[31] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 34 | assign crcOut[24] = (crcIn[0] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data[0] ^ data[2] ^ data[4] ^ data[5] ^ data[7]); 35 | assign crcOut[25] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6]); 36 | assign crcOut[26] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 37 | assign crcOut[27] = (crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data[1] ^ data[3] ^ data[4] ^ data[5] ^ data[7]); 38 | assign crcOut[28] = (crcIn[0] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ data[0] ^ data[4] ^ data[5] ^ data[6]); 39 | assign crcOut[29] = (crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[5] ^ data[6] ^ data[7]); 40 | assign crcOut[30] = (crcIn[0] ^ crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[6] ^ data[7]); 41 | assign crcOut[31] = (crcIn[1] ^ crcIn[7] ^ data[1] ^ data[7]); 42 | endmodule 43 | `default_nettype wire 44 | -------------------------------------------------------------------------------- /verilog/rtl/gpu.v: -------------------------------------------------------------------------------- 1 | // Graphics Processing Unit for Small Color LCDs 12/3/2020 2 | 3 | // Perhaps a wee bit smaller than nVidia... 4 | // This does some math for feeding a ILI9341 or ILI9488 LCD controller. 5 | // Basic functions are: 6 | // 1. Translating a 1pbb word into a color one bit at a time. 7 | // 2. Alpha-blending two colors using 4bpp grayscale. 8 | // 3. Formatting color data for bus writes. 9 | 10 | `default_nettype none 11 | 12 | module gpu 13 | #( 14 | parameter WIDTH = 18 // data width 15 | ) 16 | ( 17 | input wire clk, 18 | input wire rst_n, 19 | input wire [1:0] sel, 20 | input wire go, // trigger CLOAD, MLOAD, MONO, GRAY 21 | output reg busy, 22 | output wire [WIDTH-1:0] y, 23 | input wire [WIDTH-1:0] a, // tos 24 | input wire [WIDTH-1:0] b // nos 25 | ); 26 | 27 | reg [17:0] pixel, fgcolor, bgcolor; 28 | assign y = pixel; 29 | 30 | // Two multipliers are used in the interpolation 31 | 32 | reg [5:0] fg, bg, gray; // 6-bit colors to interpolate 33 | wire [5:0] dark = ~gray; 34 | reg mtrig, mbusy; 35 | 36 | reg [2:0] count; 37 | reg [11:0] accf, accb; // accumulators 38 | 39 | wire [6:0] sumf = accf[11:6] + gray; 40 | wire [6:0] sumb = accb[11:6] + dark; 41 | 42 | always @(posedge clk or negedge rst_n) 43 | if (!rst_n) begin 44 | mbusy <= 1'b0; 45 | {count, accf, accb} <= 1'b0; 46 | end else begin // dual unsigned multiply 47 | if (mbusy) begin 48 | accf <= (accf[0]) ? {sumf, accf[5:1]} : {1'b0, accf[11:1]}; 49 | accb <= (accb[0]) ? {sumb, accb[5:1]} : {1'b0, accb[11:1]}; 50 | if (count) count <= count - 1'b1; 51 | else mbusy <= 1'b0; 52 | end else begin 53 | if (mtrig) begin 54 | mbusy <= 1'b1; 55 | count <= 3'd5; 56 | accf <= fg; 57 | accb <= bg; 58 | end 59 | end 60 | end 61 | 62 | wire [6:0] color = accf[11:5] + accb[11:5]; 63 | 64 | // FSM 65 | 66 | reg [WIDTH-1:0] monodata; 67 | reg [1:0] state; 68 | wire ready = ~mbusy & ~mtrig; 69 | 70 | always @* 71 | case (state) 72 | 2'd3: {fg, bg} = {fgcolor[17:12], bgcolor[17:12]}; 73 | 2'd2: {fg, bg} = {fgcolor[11:6], bgcolor[11:6]}; 74 | default: {fg, bg} = {fgcolor[5:0], bgcolor[5:0]}; 75 | endcase 76 | 77 | always @(posedge clk or negedge rst_n) 78 | if (!rst_n) begin 79 | {busy, state, mtrig} <= 1'b0; 80 | {pixel, fgcolor, bgcolor, monodata, gray} <= 1'b0; 81 | end else begin 82 | mtrig <= 1'b0; 83 | if (state) begin 84 | if (ready) begin 85 | case (state) 86 | 2'd3: {pixel[17:12], mtrig} <= {color[6:1], 1'b1}; 87 | 2'd2: {pixel[11:6], mtrig} <= {color[6:1], 1'b1}; 88 | 2'd1: {pixel[5:0], mtrig} <= {color[6:1], 1'b0}; 89 | endcase 90 | state <= state - 1'b1; 91 | end 92 | end else begin 93 | busy <= go; 94 | if (go) case (sel) 95 | 2'd0: 96 | begin 97 | fgcolor <= a[17:0]; 98 | bgcolor <= b[17:0]; 99 | end 100 | 2'd1: 101 | begin 102 | monodata <= a; 103 | end 104 | 2'd2: 105 | begin 106 | pixel <= (monodata[0]) ? fgcolor : bgcolor; 107 | monodata <= {1'b0, monodata[WIDTH-1:1]}; 108 | end 109 | default: 110 | begin 111 | gray <= {a[3:0], a[3:2]}; 112 | mtrig <= 1'b1; 113 | state <= 2'd3; 114 | end 115 | endcase 116 | end 117 | end 118 | 119 | endmodule 120 | `default_nettype wire 121 | -------------------------------------------------------------------------------- /verilog/rtl/idivu.v: -------------------------------------------------------------------------------- 1 | // Iterative unsigned divider 11/5/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | module idivu 5 | #(parameter WIDTH = 8 6 | )( 7 | input wire clk, 8 | input wire arstn, // async reset (active low) 9 | output reg busy, // 0 = ready, 1 = busy 10 | input wire go, // trigger a division 11 | input wire [2*WIDTH-1:0] dividend, 12 | input wire [WIDTH-1:0] divisor, 13 | output reg [WIDTH-1:0] quot, 14 | output reg [WIDTH-1:0] rem, 15 | output reg overflow 16 | ); 17 | 18 | reg [4:0] count; // enough for 64/32=32 divide 19 | 20 | wire [WIDTH:0] diff = {1'b0, rem[WIDTH-2:0], quot[WIDTH-1]} - {1'b0, divisor}; 21 | wire subtract = ~diff[WIDTH] | rem[WIDTH-1]; 22 | 23 | always @(posedge clk or negedge arstn) 24 | if (!arstn) begin 25 | {busy, overflow} <= 1'b0; 26 | {rem, quot, count} <= 1'b0; // optional reset 27 | end else begin 28 | if (busy) begin 29 | if (subtract) 30 | {rem, quot} <= {diff[WIDTH-1:0], quot[WIDTH-2:0], 1'b1}; 31 | else 32 | {rem, quot} <= {rem[WIDTH-2:0], quot, 1'b0}; 33 | if (count) 34 | count <= count - 1'b1; 35 | else 36 | busy <= 1'b0; 37 | end else 38 | if (go) begin 39 | if (dividend[2*WIDTH-1:WIDTH] >= divisor) begin 40 | {rem, quot} <= {2*WIDTH{1'b1}}; 41 | overflow <= 1'b1; 42 | end else begin 43 | {busy, overflow} <= 2'b10; 44 | {rem, quot} <= dividend; 45 | count <= WIDTH - 1; 46 | end 47 | end 48 | end 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /verilog/rtl/imultf.v: -------------------------------------------------------------------------------- 1 | // Iterative fractional multiplier 11/30/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | // The versatility of fractional multiply is astounding. Algorithms can tune 5 | // the operation to their needs by adjusting the number of iterations, trading 6 | // precision for speed. A `sign` option allows either signed or unsigned 7 | // operation. Unsigned supports `um*`. 8 | 9 | // Compare to C, which gives you all the bits of precision, all the time. 10 | // An iterative multiply there will cost you the maximum since you don't get to 11 | // specify how many bits of precision you actually need. 12 | 13 | // The chad CPU doesn't have +* due to the cost of multiplexers in FPGAs. 14 | // Having extra muxes after the adder affects the critical path. 15 | 16 | // a is signed or unsigned, b is unsigned with (bits-1) bits of precision. 17 | 18 | module imultf 19 | #(parameter WIDTH = 24 20 | )( 21 | input wire clk, 22 | input wire arstn, // async reset (active low) 23 | output reg busy, // 0 = ready, 1 = busy 24 | input wire go, // trigger a multiplication 25 | input wire sign, // signed if 1, unsigned if 0 26 | input wire [4:0] bits, // bits of precision to use, less 1 27 | input wire [WIDTH-1:0] a, b, // multiplier inputs 28 | output wire [2*WIDTH-1:0] p // multiplier product 29 | ); 30 | 31 | reg [4:0] count; // enough for 32x32=64 multiply 32 | reg [WIDTH-1:0] m; // multiplicand 33 | reg [2*WIDTH-1:0] acc; // accumulator 34 | reg sgn; // 1 = signed, 0 = unsigned 35 | 36 | wire [WIDTH:0] sum = {(acc[2*WIDTH-1] & sgn), acc[2*WIDTH-1:WIDTH]} 37 | + {(m[WIDTH-1] & sgn), m}; 38 | assign p = acc[2*WIDTH-1:0]; 39 | 40 | always @(posedge clk or negedge arstn) 41 | if (!arstn) begin 42 | busy <= 1'b0; 43 | {sgn, count, acc, m} <= 1'b0; // optional reset 44 | end else begin 45 | if (busy) begin 46 | acc <= (acc[0]) 47 | ? {sum, acc[WIDTH-1:1]} 48 | : {(acc[2*WIDTH-1] & sgn), acc[2*WIDTH-1:1]}; 49 | if (count) count <= count - 1'b1; 50 | else busy <= 1'b0; 51 | end else begin 52 | if (go) begin 53 | busy <= 1'b1; 54 | sgn <= sign; 55 | count <= bits; 56 | acc <= b; 57 | m <= a; 58 | end 59 | end 60 | end 61 | 62 | endmodule 63 | -------------------------------------------------------------------------------- /verilog/rtl/ishift.v: -------------------------------------------------------------------------------- 1 | // Iterative shifter 12/3/2020 BNE 2 | // This code is a gift to Divine Mother and all of creation. 3 | 4 | // Shifts are done in 6-bit chunks, then 1-bit steps to finish. 5 | // The idea is to balance execution time with mux usage to use fewer 6 | // FPGA resources yet have a reasonable execution time. 7 | 8 | module ishift 9 | #(parameter WIDTH = 32 // should be 32 to 64 10 | )( 11 | input wire clk, 12 | input wire arstn, // async reset (offset low) 13 | output reg busy, // 0 = ready, 1 = busy 14 | input wire go, // trigger a shift 15 | input wire [2:0] fmt, // 3-bit shift format 16 | input wire [5:0] cnt, // 6-bit shift coount 17 | input wire [WIDTH-1:0] a, // shifter in 18 | output reg [WIDTH-1:0] y // shifter out 19 | ); 20 | 21 | // formats: 22 | // 000 = logical right shift 23 | // 0x1 = left shift 24 | // 010 = arithmetic right shift 25 | // 1xx = rotate right, 32-bit (for SHA) 26 | 27 | reg [2:0] format; 28 | wire msb = (format[1]) ? y[WIDTH-1] : 1'b0; 29 | reg [5:0] remaining; 30 | 31 | reg [2:0] mode; // shift type: /2, /64, *2, *64 32 | always @* begin 33 | if (remaining > 5) // 001 = >>6; 011 = <<6, 1x1 = ror 6 34 | mode <= {format[2], format[0], 1'b1}; 35 | else if (go) 36 | mode <= 3'b100; // 100 = a 37 | else if (format[2]) 38 | mode <= 3'b110; // 110 = ror 1 39 | else 40 | mode <= {1'b0, format[0], 1'b0}; // 000 = >>1; 010 = <<1 41 | end 42 | 43 | wire [31:0] ror1 = {y[0], y[31:1]}; // rotate right lower 32 bits 44 | wire [31:0] ror6 = {y[5:0], y[31:6]}; 45 | 46 | wire load = (remaining) ? 1'b1 : go; // clock in a new y value 47 | always @(posedge clk) 48 | if (load) begin 49 | case (mode) 50 | 3'b000: y <= {msb, y[WIDTH-1:1]}; 51 | 3'b001: y <= {{6{msb}}, y[WIDTH-1:6]}; 52 | 3'b010: y <= {y[WIDTH-2:0], 1'b0}; 53 | 3'b011: y <= {y[WIDTH-7:0], 6'b0}; 54 | 3'b100: y <= a; 55 | 3'b110: y <= ror1; 56 | 3'b111, 3'b101: y <= ror6; 57 | endcase 58 | end 59 | 60 | always @(posedge clk or negedge arstn) 61 | if (!arstn) begin 62 | {busy, format, remaining} <= 1'b0; 63 | end else begin 64 | if (remaining) begin 65 | remaining <= remaining - ((mode[0]) ? 6'd6 : 6'd1); 66 | end else begin 67 | if (go) begin 68 | format <= fmt; 69 | if (cnt) begin 70 | busy <= 1'b1; 71 | remaining <= cnt; 72 | end 73 | end else 74 | busy <= 1'b0; 75 | end 76 | end 77 | 78 | endmodule 79 | -------------------------------------------------------------------------------- /verilog/rtl/options.vh: -------------------------------------------------------------------------------- 1 | // #defines for options 2 | 3 | `ifndef _options_vh_ 4 | `define _options_vh_ 5 | 6 | `default_nettype none 7 | 8 | // coprocessor options 9 | `define OPTIONS_IMULT // 1 10 | `define OPTIONS_IDIV // 2 11 | `define OPTIONS_ISHIFT // 4 12 | `define OPTIONS_TINYGPU // 8 13 | 14 | `define OPTIONS_COP 15 // sum of options, tells firmware what's here 15 | 16 | `endif // _options_vh_ 17 | 18 | // When synthesizing for MAX 10, including all options adds 711 LEs for 24-bit 19 | // cells. 20 | -------------------------------------------------------------------------------- /verilog/rtl/prio_enc.v: -------------------------------------------------------------------------------- 1 | // Parameterizable priority encoder 2 | // see https://github.com/yugr/primogen/blob/master/src/prio_enc.v 3 | 4 | // `y` = bit number of the highest `a` bit, 0 if none. 5 | // `a` has 2^WIDTH - 1 usable inputs. 6 | 7 | module prio_enc #( 8 | parameter WIDTH = 4 // 2^WIDTH inputs --> WIDTH outputs 9 | )( 10 | input wire [(1<= 0; w = w - 1) begin : encoder 25 | assign y[w] = |ors[w*M + 2*(1 << w) - 1:w*M + (1 << w)]; 26 | if (w > 0) begin 27 | assign ors[(w - 1)*M + (1 << w) - 1:(w - 1)*M] = y[w] ? 28 | ors[w*M + 2*(1 << w) - 1:w*M + (1 << w)] : ors[w*M + (1 << w) - 1:w*M]; 29 | end 30 | end 31 | endgenerate 32 | 33 | `else 34 | 35 | integer i, w; 36 | reg [(1<= 0; i = i - 1) begin 42 | w = 1 << i; 43 | if (|(part >> w)) 44 | y[i] = 1; 45 | // Hopefully synthesizer understands that 'part' is shrinking... 46 | part = y[i] ? part >> w : part & ((1'd1 << w) - 1'd1); 47 | end 48 | end 49 | 50 | `endif 51 | 52 | endmodule 53 | -------------------------------------------------------------------------------- /verilog/rtl/sflash.v: -------------------------------------------------------------------------------- 1 | // SPI flash interface 10/2/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | module sflash 5 | ( 6 | input wire clk, 7 | input wire arstn, // async reset 8 | // Flash Memory interface to spif 9 | output reg ready, // Ready for next byte to send 10 | input wire wr, // Flash transmit strobe 11 | input wire [7:0] din, // Flash transmit data 12 | input wire [2:0] format, // Flash format 13 | input wire [3:0] prescale, // Flash configuration setup 14 | output reg [7:0] dout, // Flash received data 15 | // SPI 6-wire connection 16 | output reg sclk, // Freq = Fclk / (2 * (prescale + 1)) 17 | output wire cs_n, 18 | input wire [3:0] qdi, 19 | output reg [3:0] qdo, 20 | output reg [3:0] oe // output enable for qdo 21 | ); 22 | 23 | // The 4-bit prescale value allows for a divisor of 2 to 32 on SCLK. 24 | // for a 50 MHz SPI clock, the maximum module clock is 1.6 GHz. 25 | 26 | // format is the bus format of the SPI: 27 | // 00x = inactive (CS# = '1') 28 | // 01x = single data rate send and receive 29 | // 100 = dual data rate send 30 | // 101 = dual data rate receive 31 | // 110 = quad data rate send 32 | // 111 = quad data rate receive 33 | 34 | assign cs_n = (format[2:1]) ? 1'b0 : 1'b1; 35 | 36 | reg [2:0] state; 37 | localparam SPI_IDLE = 3'b001; 38 | localparam SPI_RUN = 3'b010; 39 | localparam SPI_LAST = 3'b100; 40 | 41 | // SPI chip pins, GD25Q16C datasheet: 42 | // Standard SPI: SCLK, CS#, SI, SO, WP#, HOLD# 43 | // Dual SPI: SCLK, CS#, IO0, IO1, WP#, HOLD# 44 | // Quad SPI: SCLK, CS#, IO0, IO1, IO2, IO3 45 | 46 | always @* begin 47 | if (state == SPI_IDLE) 48 | oe = 4'b0000; 49 | else 50 | case (format) // {none, none, sdr, sdr, ddrT, ddrR, qdrT, qdrR} 51 | 3'b010: oe = 4'b0001; 52 | 3'b011: oe = 4'b0001; 53 | 3'b100: oe = 4'b0011; 54 | 3'b110: oe = 4'b1111; 55 | default: oe = 4'b0000; 56 | endcase 57 | end 58 | 59 | reg [3:0] divider; 60 | reg [7:0] sr; 61 | reg [3:0] count; 62 | reg phase; 63 | 64 | // Outgoing data to the SPI flash is clocked in on the rising edge. 65 | // The controller shifts it out on the falling edge. 66 | // Data from SPI flash clocks out on falling edge, GD25Q16C delay = 0.7 to 8 ns. 67 | // Use SDC constraints to make sure the qdi input can tolerate 0.7ns hold time. 68 | // SCLK starts high and ends high. 69 | // sclk ----------__________----------__________----------__________---------- 70 | // qdi ...........xxxxxxxddddddddddddddd..................................... 71 | // sample qdi here: ------------------^ 72 | // qdo ...........oooooooooooooooooooo....................................... 73 | // register qdo:--^ 74 | // SPI_IDLE | SPI_RUN 75 | 76 | always @(posedge clk or negedge arstn) 77 | if (!arstn) begin 78 | {divider, qdo, dout, sr, phase} <= 1'b0; 79 | {ready, sclk} <= 2'b11; 80 | state <= SPI_IDLE; 81 | count <= 4'd8; 82 | end else 83 | case (state) 84 | SPI_IDLE: 85 | if (wr) begin 86 | sr <= din; 87 | ready <= 1'b0; 88 | phase <= 1'b0; 89 | case (format[2:1]) 90 | 2'b10: count <= 4'd4; 91 | 2'b11: count <= 4'd2; 92 | default: count <= 4'd8; 93 | endcase 94 | state <= SPI_RUN; 95 | end 96 | SPI_RUN: 97 | begin 98 | if (divider) 99 | divider <= divider - 4'd1; 100 | else begin 101 | divider <= prescale; 102 | if (!phase) begin 103 | case (format[2:1]) 104 | 2'b10: {qdo[1:0], sr} <= {sr, qdi[1:0]}; 105 | 2'b11: {qdo, sr} <= {sr, qdi}; 106 | default: {qdo[0], sr} <= {sr, qdi[1]}; 107 | endcase 108 | if (count) 109 | count <= count - 3'd1; 110 | else 111 | state <= SPI_LAST; 112 | end 113 | if (count) sclk <= ~sclk; 114 | else sclk <= 1'b1; 115 | phase <= ~phase; 116 | end 117 | end 118 | SPI_LAST: begin 119 | state <= SPI_IDLE; 120 | dout <= sr; 121 | ready <= 1'b1; 122 | end 123 | default: 124 | state <= SPI_IDLE; 125 | endcase 126 | 127 | endmodule 128 | 129 | -------------------------------------------------------------------------------- /verilog/rtl/spram.v: -------------------------------------------------------------------------------- 1 | // Generic synchronous read/write single-port RAM 10/16/2021 BNE 2 | 3 | // To do: Add byte lane write enables. 4 | // For now, they are not used. c! and w! use RMW. 5 | 6 | module spram 7 | #(parameter ADDR_WIDTH = 10, 8 | parameter DATA_WIDTH = 16 9 | ) 10 | ( input wire clk, 11 | input wire [ADDR_WIDTH-1:0] addr, 12 | input wire [DATA_WIDTH-1:0] din, 13 | output reg [DATA_WIDTH-1:0] dout, 14 | input wire we, 15 | input wire re, 16 | input wire [((DATA_WIDTH + 7) / 8) - 1:0] lane 17 | ); 18 | 19 | reg [DATA_WIDTH-1:0] mem [2**ADDR_WIDTH-1:0]; 20 | 21 | always @ (posedge clk) begin 22 | if (we) 23 | mem[addr] <= din; 24 | else if (re) 25 | dout <= mem[addr]; 26 | end 27 | 28 | endmodule 29 | 30 | // This is supported by typical FPGAs and also OpenRAM. 31 | // The "if (re)" can be removed for FPGA convenience. 32 | 33 | // OpenRAM usually has a bi-directional bus whose direction is determined by 34 | // we_b and cs_b. The logic for this would be: 35 | // we_b = ~we 36 | // ce_b = ~we & ~re 37 | // BusDirection = we, arrange delay for bus switching to and from Z 38 | -------------------------------------------------------------------------------- /verilog/rtl/stack.v: -------------------------------------------------------------------------------- 1 | // Stack definition from J1 family 2 | // Made from shift registers 3 | 4 | module stack 5 | #( 6 | parameter WIDTH = 18, 7 | parameter DEPTH = 16 8 | ) 9 | ( 10 | input wire clk, 11 | input wire hold, 12 | output wire [WIDTH-1:0] rd, 13 | input wire we, 14 | input wire [1:0] delta, // {none, up, down, down} 15 | input wire [WIDTH-1:0] wd 16 | ); 17 | 18 | localparam BITS = (WIDTH * DEPTH) - 1; 19 | localparam EMPTY = 32'h55AA55AA; 20 | wire move = delta[0] | delta[1]; 21 | 22 | reg [WIDTH-1:0] head; 23 | reg [BITS:0] tail; 24 | wire [WIDTH-1:0] headN; 25 | wire [BITS:0] tailN; 26 | 27 | assign headN = we ? wd : tail[WIDTH-1:0]; 28 | assign tailN = delta[1] ? 29 | {EMPTY[WIDTH-1:0], tail[BITS:WIDTH]} : 30 | {tail[BITS-WIDTH:0], head}; 31 | 32 | always @(posedge clk) 33 | if (!hold) begin 34 | if (we | move) head <= headN; 35 | if (move) tail <= tailN; 36 | end 37 | 38 | assign rd = head; 39 | 40 | endmodule 41 | -------------------------------------------------------------------------------- /verilog/rtl/uart.v: -------------------------------------------------------------------------------- 1 | // Unbuffered UART with FIFO-compatible interface 11/6/2020 BNE 2 | // License: This code is a gift to mankind and is dedicated to peace on Earth. 3 | 4 | module uart 5 | ( 6 | input wire clk, 7 | input wire arstn, // async reset (active low) 8 | output wire ready, // Ready for next byte to send 9 | input wire wr, // UART transmit strobe 10 | input wire [7:0] din, // UART transmit data 11 | output reg full, // UART has received a byte 12 | input wire rd, // UART received strobe (clears full) 13 | output reg [7:0] dout, // UART received data 14 | input wire [15:0] bitperiod, // Clocks per serial bit 15 | input wire rxd, // Must be externally synchronized 16 | output reg txd 17 | ); 18 | 19 | // Baud rate is BPS = clk/bitperiod. Example: 100M/868 = 115200 BPS. 20 | reg [11:0] baudint; 21 | reg [3:0] baudfrac; 22 | reg tick; 23 | always @(posedge clk or negedge arstn) 24 | if (!arstn) begin 25 | {baudint, baudfrac, tick} <= 1'b0; 26 | end else begin 27 | tick <= 1'b0; 28 | if (baudint) 29 | baudint <= baudint - 1'b1; 30 | else begin 31 | tick <= 1'b1; 32 | if (bitperiod[3:0] > baudfrac) // fractional divider: 33 | baudint <= bitperiod[15:4]; // stretch by Frac/16 clocks 34 | else baudint <= bitperiod[15:4] - 1'b1; 35 | baudfrac <= baudfrac + 1'b1; // 16 ticks/bit 36 | end 37 | end 38 | 39 | reg tnext, error; 40 | wire startbit = ~rxd & ~error; 41 | reg [7:0] inreg; // pending transmit byte 42 | reg pending; 43 | 44 | assign ready = ~pending; 45 | 46 | // UART 47 | reg [7:0] txstate, rxstate, txreg, rxreg; 48 | always @(posedge clk or negedge arstn) 49 | if (!arstn) begin 50 | {full, error, pending, txreg, tnext, txd} <= 2'b11; 51 | {txstate, rxstate, rxreg, dout, inreg} <= 1'b0; 52 | end else begin 53 | if (tick) begin 54 | // Transmitter 55 | txd <= tnext; 56 | if (txstate) begin 57 | if (!txstate[3:0]) 58 | {txreg, tnext} <= {1'b1, txreg[7:0]}; 59 | txstate <= txstate - 1'b1; 60 | end else begin 61 | if (pending) begin 62 | {pending, tnext} <= 1'b0; // n,8,1 63 | txreg <= inreg; 64 | txstate <= 8'h9F; 65 | end 66 | end 67 | // Receiver 68 | if (rxstate) begin 69 | if (rxstate[3:0] == 4'd1) 70 | case (rxstate[7:4]) 71 | 4'b1001: 72 | if (rxd) rxstate <= 8'd0; // false start 73 | 4'b0000: 74 | if (rxd) {dout, full} <= {rxreg, 1'b1}; 75 | else error <= 1'b1; // '0' at the stop bit (or BREAK) 76 | default: 77 | rxreg <= {rxd, rxreg[7:1]}; 78 | endcase 79 | rxstate <= rxstate - 1'b1; 80 | end else begin 81 | error <= error & ~rxd; // stop or mark ('1') clears error 82 | if (startbit) rxstate <= 8'h98; // will be sampled mid-bit 83 | end 84 | end 85 | if (rd) full <= 1'b0; // reading clears full 86 | // Transmit input register gives firmware an entire character period to respond 87 | // to ready with the next byte to elimnate character spacing. 88 | if (wr) 89 | if (!pending) begin // retrigger transmission 90 | inreg <= din; 91 | pending <= 1'b1; 92 | end 93 | end 94 | endmodule 95 | -------------------------------------------------------------------------------- /verilog/testbench/cdc_tb.v: -------------------------------------------------------------------------------- 1 | // CDC testbench 11/6/2020 BNE 2 | 3 | `timescale 10ps/10ps 4 | 5 | module cdc_tb(); 6 | 7 | reg clk = 1; 8 | reg a = 0; 9 | wire y; 10 | 11 | cdc u1 ( 12 | .clk (clk), 13 | .a (a), 14 | .y (y) 15 | ); 16 | 17 | always #500 clk <= !clk; 18 | always #3217 a <= !a; 19 | 20 | // Main Testing: 21 | initial 22 | begin 23 | repeat (1000) @(posedge clk); 24 | $stop(); 25 | end 26 | 27 | initial 28 | begin 29 | // Required to dump signals to EPWave 30 | $dumpfile("dump.vcd"); 31 | $dumpvars(0); 32 | end 33 | 34 | endmodule 35 | 36 | -------------------------------------------------------------------------------- /verilog/testbench/coproc_tb.v: -------------------------------------------------------------------------------- 1 | // Coprocessor testbench 12/17/2020 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module coproc_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | 10 | reg [10:0] sel = 0; 11 | reg go = 0; 12 | wire [17:0] y; 13 | reg [17:0] tos = 0; 14 | reg [17:0] nos = 0; 15 | reg [17:0] w = 0; 16 | 17 | coproc #(18) u1 ( 18 | .clk (clk), 19 | .arstn (rst_n), 20 | .sel (sel), 21 | .go (go), 22 | .y (y), 23 | .a (tos), 24 | .b (nos), 25 | .c (w) 26 | ); 27 | 28 | always #5 clk <= !clk; 29 | 30 | // Poll the busy flag in a loop 31 | task WAIT; 32 | begin 33 | sel <= 0; 34 | @(posedge clk); 35 | while (y) @(posedge clk); 36 | end 37 | endtask 38 | 39 | // Trigger coprocessor operation 40 | task TEST; 41 | input [10:0] selin; // select 42 | input [17:0] ain; // TOS 43 | input [17:0] bin; // NOS 44 | input [17:0] cin; // W 45 | begin 46 | @(posedge clk); 47 | tos <= ain; nos <= bin; w <= cin; sel <= selin; 48 | @(posedge clk); go <= 1'b1; 49 | @(posedge clk); go <= 1'b0; 50 | end 51 | endtask 52 | 53 | // Main Testing: 54 | initial 55 | begin 56 | #7 57 | rst_n <= 1'b1; 58 | TEST(11'h18, 18'o777371, 18'o001116, 0); // set colors 59 | TEST(11'h38, 18'o520252, 18'd0, 0); 60 | repeat (10) TEST(11'h58, 18'd0, 18'd0, 0); // monochrome out 61 | TEST(11'h78, 18'o26, 18'd0, 0); // gray 62 | WAIT(); 63 | TEST(11'h78, 18'o77, 18'd0, 0); // more gray 64 | WAIT(); 65 | repeat (200) @(posedge clk); 66 | $display("Testbench Finished"); 67 | $stop(); 68 | end 69 | 70 | initial 71 | begin 72 | // Required to dump signals to EPWave 73 | $dumpfile("dump.vcd"); 74 | $dumpvars(0); 75 | end 76 | 77 | endmodule 78 | -------------------------------------------------------------------------------- /verilog/testbench/crc32.v: -------------------------------------------------------------------------------- 1 | `default_nettype none 2 | 3 | // https://bues.ch/h/crcgen 4 | 5 | module crc ( 6 | input [31:0] crcIn, 7 | input [7:0] data, 8 | output [31:0] crcOut, 9 | ); 10 | assign crcOut[0] = (crcIn[2] ^ crcIn[8] ^ data[2]); 11 | assign crcOut[1] = (crcIn[0] ^ crcIn[3] ^ crcIn[9] ^ data[0] ^ data[3]); 12 | assign crcOut[2] = (crcIn[0] ^ crcIn[1] ^ crcIn[4] ^ crcIn[10] ^ data[0] ^ data[1] ^ data[4]); 13 | assign crcOut[3] = (crcIn[1] ^ crcIn[2] ^ crcIn[5] ^ crcIn[11] ^ data[1] ^ data[2] ^ data[5]); 14 | assign crcOut[4] = (crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[6] ^ crcIn[12] ^ data[0] ^ data[2] ^ data[3] ^ data[6]); 15 | assign crcOut[5] = (crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[7] ^ crcIn[13] ^ data[1] ^ data[3] ^ data[4] ^ data[7]); 16 | assign crcOut[6] = (crcIn[4] ^ crcIn[5] ^ crcIn[14] ^ data[4] ^ data[5]); 17 | assign crcOut[7] = (crcIn[0] ^ crcIn[5] ^ crcIn[6] ^ crcIn[15] ^ data[0] ^ data[5] ^ data[6]); 18 | assign crcOut[8] = (crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ crcIn[16] ^ data[1] ^ data[6] ^ data[7]); 19 | assign crcOut[9] = (crcIn[7] ^ crcIn[17] ^ data[7]); 20 | assign crcOut[10] = (crcIn[2] ^ crcIn[18] ^ data[2]); 21 | assign crcOut[11] = (crcIn[3] ^ crcIn[19] ^ data[3]); 22 | assign crcOut[12] = (crcIn[0] ^ crcIn[4] ^ crcIn[20] ^ data[0] ^ data[4]); 23 | assign crcOut[13] = (crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[21] ^ data[0] ^ data[1] ^ data[5]); 24 | assign crcOut[14] = (crcIn[1] ^ crcIn[2] ^ crcIn[6] ^ crcIn[22] ^ data[1] ^ data[2] ^ data[6]); 25 | assign crcOut[15] = (crcIn[2] ^ crcIn[3] ^ crcIn[7] ^ crcIn[23] ^ data[2] ^ data[3] ^ data[7]); 26 | assign crcOut[16] = (crcIn[0] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[24] ^ data[0] ^ data[2] ^ data[3] ^ data[4]); 27 | assign crcOut[17] = (crcIn[0] ^ crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[25] ^ data[0] ^ data[1] ^ data[3] ^ data[4] ^ data[5]); 28 | assign crcOut[18] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ crcIn[26] ^ data[0] ^ data[1] ^ data[2] ^ data[4] ^ data[5] ^ data[6]); 29 | assign crcOut[19] = (crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ crcIn[27] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6] ^ data[7]); 30 | assign crcOut[20] = (crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[28] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 31 | assign crcOut[21] = (crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ crcIn[29] ^ data[2] ^ data[4] ^ data[5] ^ data[7]); 32 | assign crcOut[22] = (crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ crcIn[30] ^ data[2] ^ data[3] ^ data[5] ^ data[6]); 33 | assign crcOut[23] = (crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ crcIn[31] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 34 | assign crcOut[24] = (crcIn[0] ^ crcIn[2] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data[0] ^ data[2] ^ data[4] ^ data[5] ^ data[7]); 35 | assign crcOut[25] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[5] ^ crcIn[6] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[5] ^ data[6]); 36 | assign crcOut[26] = (crcIn[0] ^ crcIn[1] ^ crcIn[2] ^ crcIn[3] ^ crcIn[4] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[2] ^ data[3] ^ data[4] ^ data[6] ^ data[7]); 37 | assign crcOut[27] = (crcIn[1] ^ crcIn[3] ^ crcIn[4] ^ crcIn[5] ^ crcIn[7] ^ data[1] ^ data[3] ^ data[4] ^ data[5] ^ data[7]); 38 | assign crcOut[28] = (crcIn[0] ^ crcIn[4] ^ crcIn[5] ^ crcIn[6] ^ data[0] ^ data[4] ^ data[5] ^ data[6]); 39 | assign crcOut[29] = (crcIn[0] ^ crcIn[1] ^ crcIn[5] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[5] ^ data[6] ^ data[7]); 40 | assign crcOut[30] = (crcIn[0] ^ crcIn[1] ^ crcIn[6] ^ crcIn[7] ^ data[0] ^ data[1] ^ data[6] ^ data[7]); 41 | assign crcOut[31] = (crcIn[1] ^ crcIn[7] ^ data[1] ^ data[7]); 42 | endmodule 43 | -------------------------------------------------------------------------------- /verilog/testbench/fdata.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bradleyeckert/chad/f164a7a3727fc1142e24354a55406289d26da379/verilog/testbench/fdata.bin -------------------------------------------------------------------------------- /verilog/testbench/flashsim.v: -------------------------------------------------------------------------------- 1 | 2 | `timescale 1ns / 1ns 3 | 4 | module flashsim 5 | #( 6 | parameter FILENAME = "fdata.hex" 7 | ) 8 | ( 9 | input wire clk, 10 | input wire arstn, // async reset 11 | // Flash Memory interface to spif 12 | output reg ready, // Ready for next byte to send 13 | input wire wr, // Flash transmit strobe 14 | input wire [7:0] din, // Flash transmit data 15 | input wire [2:0] format, // Flash format 16 | input wire [3:0] prescale, // Flash configuration setup 17 | output reg [7:0] dout // Flash received data 18 | ); 19 | 20 | // format is the bus format of the SPI: 21 | // 000 = inactive (CS# = '1') 22 | // other = active, various sizes and bus drives: SDR, DDR, QDR 23 | 24 | integer file; 25 | integer fstate; 26 | integer delay; 27 | parameter FLASH_PERIOD = 2; 28 | reg [23:0] faddr; 29 | 30 | initial 31 | begin 32 | fstate = 1; 33 | delay = FLASH_PERIOD; 34 | faddr = 24'h000000; 35 | ready = 1'b0; 36 | dout = 8'h00; 37 | file = $fopen(FILENAME, "rb"); 38 | end 39 | 40 | always @(posedge clk) begin 41 | if (wr) begin 42 | if (ready) begin 43 | delay <= FLASH_PERIOD; 44 | ready <= 1'b0; 45 | case (fstate) 46 | 0: if (!format) // wait for CS# = '1' 47 | begin 48 | fstate <= 1; 49 | dout <= 8'hFF; 50 | end 51 | 1: if (format) // wait for CS# = '0' 52 | if (din == 8'h0B) // "fast read" command 53 | fstate <= 2; 54 | else if (din == 8'h05) // "status" command 55 | fstate <= 7; 56 | else 57 | fstate <= 0; 58 | 2: begin 59 | faddr[23:16] <= din; 60 | fstate <= 3; 61 | end 62 | 3: begin 63 | faddr[15:8] <= din; 64 | fstate <= 4; 65 | end 66 | 4: begin 67 | faddr[7:0] <= din; 68 | fstate <= 5; 69 | end 70 | 5: begin 71 | fstate <= 6; 72 | if (file == 0) begin 73 | $display("\nCan't open file %s\n", FILENAME); 74 | fstate <= 0; 75 | end else begin 76 | if ($fseek(file, faddr, 0) == -1) begin 77 | $display("ERROR: fseek failed"); 78 | fstate <= 0; 79 | end 80 | end 81 | end 82 | 6: if (!format) 83 | fstate <= 1; 84 | else begin 85 | dout <= $fgetc(file); 86 | if ($feof(file)) fstate <= 1; 87 | end 88 | 7: if (!format) 89 | fstate <= 1; 90 | else 91 | dout <= 8'h00; 92 | default: fstate <= 0; 93 | endcase 94 | end else begin 95 | $display("\nERROR: Writing to a not-ready FLASH"); 96 | $stop; 97 | end 98 | end 99 | else begin 100 | if (delay) delay <= delay - 1; 101 | else begin 102 | ready <= 1'b1; 103 | if (!format) fstate <= 1; 104 | end 105 | end 106 | end 107 | 108 | endmodule 109 | -------------------------------------------------------------------------------- /verilog/testbench/gecko_tb.v: -------------------------------------------------------------------------------- 1 | // gecko testbench 10/26/2020 BNE 2 | // Run this for 5 us 3 | // expected $display output: 08 01 80 72 78 59 91 de ... 4 | 5 | `timescale 1ns/10ps 6 | 7 | module gecko_tb(); 8 | 9 | reg clk = 1; 10 | reg rst_n = 0; 11 | 12 | reg clken = 1'b0; // clock enable 13 | wire ready; // initializing 14 | reg next = 1'b0; // byte trigger 15 | wire [7:0] dout; // PRNG output 16 | 17 | // reg [55:0] widekey = 56'h12345687654321; 18 | reg [55:0] widekey = 56'h1; 19 | reg [3:0] idx = 0; 20 | wire [7:0] key = widekey[7:0]; 21 | 22 | gecko u1 ( 23 | .clk (clk), 24 | .rst_n (rst_n), 25 | .clken (clken), 26 | .ready (ready), 27 | .next (next), 28 | .key (key), 29 | .dout (dout) 30 | ); 31 | 32 | always #5 clk <= !clk; 33 | 34 | task NEXT; // get next PRNG byte 35 | reg [7:0] x; 36 | begin 37 | @(posedge ready); x = dout; 38 | @(posedge clk); next <= 1'b1; 39 | @(posedge clk); next <= 1'b0; 40 | $display("%Xh", x); 41 | end 42 | endtask // NEXT 43 | 44 | // Main Testing: 45 | initial 46 | begin 47 | #7 rst_n = 1'b1; 48 | @(posedge clk); 49 | clken <= 1'b1; 50 | while (idx < 7) begin // load the key 51 | @(posedge clk); 52 | widekey <= {8'h00, widekey[55:8]}; 53 | idx = idx + 1; 54 | end 55 | repeat (1000) NEXT(); 56 | @(posedge ready); 57 | #100 58 | $stop(); 59 | end 60 | 61 | initial 62 | begin 63 | // Required to dump signals to EPWave 64 | $dumpfile("dump.vcd"); 65 | $dumpvars(0); 66 | end 67 | 68 | endmodule 69 | -------------------------------------------------------------------------------- /verilog/testbench/gpu_tb.v: -------------------------------------------------------------------------------- 1 | // GPU testbench 12/3/2020 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module gpu_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | 10 | wire busy; 11 | reg [2:0] sel; 12 | reg go = 0; 13 | wire [17:0] y; 14 | reg [17:0] a; 15 | reg [17:0] b; 16 | 17 | gpu #(18) u1 ( 18 | .clk (clk), 19 | .rst_n (rst_n), 20 | .sel (sel), 21 | .go (go), 22 | .busy (busy), 23 | .y (y), 24 | .a (a), 25 | .b (b) 26 | ); 27 | 28 | always #5 clk <= !clk; 29 | 30 | // Trigger GPU operation 31 | task TEST; 32 | input [17:0] ain; // TOS 33 | input [17:0] bin; // NOS 34 | input [2:0] selin; // select 35 | begin 36 | @(posedge clk); 37 | a <= ain; b <= bin; sel <= selin; 38 | @(posedge clk); go <= 1'b1; 39 | @(posedge clk); go <= 1'b0; 40 | @(negedge busy); 41 | end 42 | endtask 43 | 44 | // Main Testing: 45 | initial 46 | begin 47 | #7 48 | rst_n <= 1'b1; 49 | TEST(18'o777371, 18'o001116, 0); // set colors 50 | TEST(18'o520252, 18'd0, 1); 51 | repeat (10) TEST(18'd0, 18'd0, 2); // monochrome out 52 | TEST(18'o26, 18'd0, 3); // gray 53 | TEST(18'o77, 18'd0, 3); // more gray 54 | repeat (200) @(posedge clk); 55 | $display("Testbench Finished"); 56 | $stop(); 57 | end 58 | 59 | initial 60 | begin 61 | // Required to dump signals to EPWave 62 | $dumpfile("dump.vcd"); 63 | $dumpvars(0); 64 | end 65 | 66 | endmodule 67 | -------------------------------------------------------------------------------- /verilog/testbench/idivu_tb.v: -------------------------------------------------------------------------------- 1 | // Divider testbench 11/5/2020 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module idivu_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | 10 | wire busy; 11 | reg go = 0; 12 | reg [15:0] dividend = 46845; 13 | reg [7:0] divisor = 200; 14 | wire [7:0] quot; 15 | wire [7:0] rem; 16 | wire overflow; 17 | 18 | idivu u1 ( 19 | .clk (clk), 20 | .arstn (rst_n), 21 | .busy (busy), 22 | .go (go), 23 | .dividend (dividend), 24 | .divisor (divisor), 25 | .quot (quot), 26 | .rem (rem), 27 | .overflow (overflow) 28 | ); 29 | 30 | always #5 clk <= !clk; 31 | 32 | // Main Testing: 33 | initial 34 | begin 35 | #7 36 | rst_n <= 1'b1; 37 | @(posedge clk); go <= 1'b1; 38 | @(posedge clk); go <= 1'b0; 39 | repeat (200) @(posedge clk); 40 | $stop(); 41 | end 42 | 43 | initial 44 | begin 45 | // Required to dump signals to EPWave 46 | $dumpfile("dump.vcd"); 47 | $dumpvars(0); 48 | end 49 | 50 | endmodule 51 | -------------------------------------------------------------------------------- /verilog/testbench/imultf_tb.v: -------------------------------------------------------------------------------- 1 | // Multipler testbench 11/30/2020 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module imultf_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | 10 | wire busy; 11 | reg go = 0; 12 | reg sign = 1; 13 | reg [7:0] a = 99; 14 | reg [7:0] b = 43; 15 | reg [4:0] bits = 5; 16 | wire [15:0] p; 17 | // a is signed, b is unsigned 18 | 19 | // This kind of multiplier lets you trade precision for speed. 20 | // Tests: 21 | // 99 * (43/64) = 4284h = 66.515625 22 | // -123 * (43/64) = AD5Ch = -52A4h = -82.640625 23 | 24 | imultf #(8) u1 ( 25 | .clk (clk), 26 | .arstn (rst_n), 27 | .busy (busy), 28 | .go (go), 29 | .sign (sign), 30 | .bits (bits), 31 | .a (a), 32 | .b (b), 33 | .p (p) 34 | ); 35 | 36 | always #5 clk <= !clk; 37 | 38 | // Trigger a multiply 39 | reg signed [7:0] ns; 40 | wire signed [15:0] ps = p; 41 | reg [8:0] denominator; 42 | real actual, expected; 43 | task TEST; 44 | input [7:0] n; 45 | input [7:0] u; 46 | input [5:0] count; 47 | input is_signed; 48 | begin 49 | ns <= n; 50 | denominator <= 1 << (count + 1); 51 | @(posedge clk); 52 | a <= n; b <= u; bits <= count; 53 | sign <= is_signed; 54 | @(posedge clk); go <= 1'b1; 55 | @(posedge clk); go <= 1'b0; 56 | @(negedge busy); 57 | if (is_signed) begin 58 | expected = $itor(ns) * $itor(u) / $itor(denominator); 59 | actual = $itor(ps) / $itor(256); 60 | $display("(%d * %d) / %d produces %f (%f)", ns, u, denominator, actual, expected); 61 | end else begin 62 | expected = $itor(n) * $itor(u) / $itor(1 << (count + 1)); 63 | actual = $itor(p) / $itor(256); 64 | $display("(%d * %d) / %d produces %f (%f)", n, u, denominator, actual, expected); 65 | end 66 | end 67 | endtask 68 | 69 | // Main Testing: 70 | initial 71 | begin 72 | #7 73 | rst_n <= 1'b1; 74 | TEST(99, 43, 5, 1); 75 | if (p != 16'h4284) $error("Test 1 failed"); 76 | TEST(-123, 43, 5, 1); 77 | if (p != 16'hAD5C) $error("Test 2 failed"); 78 | TEST(255, 255, 7, 0); // -1 -1 um* test 79 | if (p != 16'hFE01) $error("Test 3 failed"); 80 | repeat (200) @(posedge clk); 81 | $display("Testbench Finished"); 82 | $stop(); 83 | end 84 | 85 | initial 86 | begin 87 | // Required to dump signals to EPWave 88 | $dumpfile("dump.vcd"); 89 | $dumpvars(0); 90 | end 91 | 92 | endmodule 93 | -------------------------------------------------------------------------------- /verilog/testbench/ishift_tb.v: -------------------------------------------------------------------------------- 1 | // Shifter testbench 12/3/2020 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module ishift_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | 10 | wire busy; 11 | reg go = 0; 12 | reg [2:0] fmt = 0; 13 | reg [5:0] cnt = 2; 14 | reg [31:0] a = 100; 15 | wire [31:0] y; 16 | 17 | ishift u1 ( 18 | .clk (clk), 19 | .arstn (rst_n), 20 | .busy (busy), 21 | .go (go), 22 | .fmt (fmt), 23 | .cnt (cnt), 24 | .a (a), 25 | .y (y) 26 | ); 27 | 28 | always #5 clk <= !clk; 29 | 30 | // Trigger a shift using (data, count, format) 31 | // format: 0 to 3 = >>1, <<1, /2, *2 32 | reg signed [31:0] is_data; 33 | wire signed [31:0] ys = y; 34 | task TEST; 35 | input [31:0] i_data; 36 | input [5:0] i_cnt; 37 | input [2:0] i_fmt; 38 | begin 39 | is_data <= i_data; 40 | @(posedge clk); 41 | a <= i_data; 42 | cnt <= i_cnt; 43 | fmt <= i_fmt; 44 | @(posedge clk); go <= 1'b1; 45 | @(posedge clk); go <= 1'b0; 46 | @(negedge busy); 47 | case (i_fmt) 48 | 3'd0: $display("Unsigned %d >> %d produces %d", i_data, i_cnt, y); 49 | 3'd1: $display("Unsigned %d << %d produces %d", i_data, i_cnt, y); 50 | 3'd2: $display("Signed %d >> %d produces %d", is_data, i_cnt, ys); 51 | 3'd3: $display("Signed %d << %d produces %d", is_data, i_cnt, ys); 52 | 3'd4: $display("%x ROR %d produces %x", i_data, i_cnt, y); 53 | endcase 54 | end 55 | endtask 56 | 57 | // Main Testing: 58 | initial 59 | begin 60 | #7 61 | rst_n <= 1'b1; 62 | TEST( 1000000, 8, 0); // LSR 63 | TEST( 10000, 4, 1); // LSL 64 | TEST( -1000000, 3, 2); // ASR 65 | TEST( -1000000, 3, 0); // LSR 66 | TEST( -1000, 4, 3); // ASL 67 | TEST(32'h80000405, 4, 4); // ROR 68 | TEST(32'h50000678, 8, 4); // ROR 69 | repeat (20000) @(posedge clk); 70 | $stop(); 71 | end 72 | 73 | initial 74 | begin 75 | // Required to dump signals to EPWave 76 | $dumpfile("dump.vcd"); 77 | $dumpvars(0); 78 | end 79 | 80 | endmodule 81 | -------------------------------------------------------------------------------- /verilog/testbench/nopll.v: -------------------------------------------------------------------------------- 1 | // Simulate a PLL the simplest way possible 2 | 3 | `timescale 1 ns / 1 ps 4 | module clkgen ( 5 | input wire CLKI, 6 | output wire CLKOP, 7 | output wire LOCK 8 | ); 9 | 10 | assign CLKOP = CLKI; 11 | assign LOCK = 1'b1; 12 | 13 | endmodule 14 | -------------------------------------------------------------------------------- /verilog/testbench/peripherals/lcdcon_tb.v: -------------------------------------------------------------------------------- 1 | // LCDCON testbench 12/16/20 BNE 2 | 3 | `timescale 1ns/10ps 4 | 5 | module lcdcon_tb(); 6 | 7 | reg clk = 1; 8 | reg rst_n = 0; 9 | // Wishbone Bob 10 | reg [2:0] adr_i = 0; // address o 11 | wire [7:0] dat_o; // data out i 12 | reg [17:0] dat_i = 0; // data in o 13 | reg we_i = 0; // 1 = write, 0 = read o 14 | reg stb_i = 0; // strobe o 15 | wire ack_o; // acknowledge i 16 | // LCD module with 8-bit bus and internal frame buffer 17 | reg [7:0] lcd_di = 0; // read data o 18 | wire [17:0] lcd_do; // write data i 19 | wire lcd_oe; // lcd_d output enable i 20 | wire lcd_rd; // RDX pin i 21 | wire lcd_wr; // WRX pin i 22 | wire lcd_rs; // DCX pin i 23 | wire lcd_cs; // CSX pin i 24 | wire lcd_rst; // RESET pin, active low i 25 | 26 | lcdcon u1 ( 27 | .clk (clk ), 28 | .rst_n (rst_n ), 29 | .adr_i (adr_i ), 30 | .dat_o (dat_o ), 31 | .dat_i (dat_i ), 32 | .we_i (we_i ), 33 | .stb_i (stb_i ), 34 | .ack_o (ack_o ), 35 | .lcd_di (lcd_di), 36 | .lcd_do (lcd_do), 37 | .lcd_oe (lcd_oe), 38 | .lcd_rd (lcd_rd), 39 | .lcd_wr (lcd_wr), 40 | .lcd_rs (lcd_rs), 41 | .lcd_cs (lcd_cs), 42 | .lcd_rst (lcd_rst) 43 | ); 44 | 45 | task READ; // Wishbone Read 46 | input [2:0] address; 47 | begin 48 | @(posedge clk); 49 | we_i <= 1'b0; stb_i <= 1'b1; adr_i <= address; 50 | @(posedge ack_o); 51 | @(posedge clk); stb_i <= 1'b0; 52 | $display("Wishbone Read [%Xh] = %Xh at %0t", adr_i, dat_o, $time); 53 | @(negedge ack_o); 54 | end 55 | endtask 56 | 57 | task WRITE; // Wishbone Write 58 | input [2:0] address; 59 | input [17:0] data; 60 | begin 61 | @(posedge clk); 62 | we_i <= 1'b1; stb_i <= 1'b1; adr_i <= address; dat_i <= data; 63 | @(posedge ack_o); 64 | @(posedge clk); stb_i <= 1'b0; 65 | $display("Wishbone Write %Xh to [%Xh] at %0t", dat_i, adr_i, $time); 66 | @(negedge ack_o); 67 | end 68 | endtask 69 | 70 | always #5 clk <= !clk; 71 | 72 | // Main Testing: 73 | initial 74 | begin 75 | #7 76 | rst_n <= 1'b1; 77 | $display("Register Setup"); 78 | WRITE(5, 12'o0403); // write timing 79 | WRITE(6, 12'o1705); // read timing 80 | WRITE(7, 1); // release reset 81 | $display("Write to MADCTL"); 82 | WRITE(1, 8'h36); // control byte 83 | WRITE(0, 8'h55); // data byte 84 | lcd_di = 8'hA5; 85 | $display("Read from RDDPM"); 86 | WRITE(2, 0); 87 | WRITE(1, 8'h0A); // control byte 88 | READ(0); 89 | READ(0); 90 | WRITE(2, 0); 91 | $display("Write GRAM"); 92 | WRITE(3, 18'o767574); 93 | WRITE(2, 0); 94 | WRITE(4, 0); // direct drive all pins off 95 | repeat (200) @(posedge clk); 96 | $stop(); 97 | end 98 | 99 | initial 100 | begin 101 | // Required to dump signals to EPWave 102 | $dumpfile("dump.vcd"); 103 | $dumpvars(0); 104 | end 105 | 106 | endmodule 107 | -------------------------------------------------------------------------------- /verilog/testbench/prio_enc_tb.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 100 ps 2 | 3 | module prio_enc_tb(); 4 | 5 | parameter WIDTH=4; 6 | 7 | reg [(1<