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 |