├── .github └── workflows │ └── ci.yml ├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── compile.py ├── fpga ├── 7seg │ ├── LispMicrocontroller.qpf │ ├── LispMicrocontroller.qsf │ ├── blink.lisp │ ├── counter.lisp │ ├── fibonacci.lisp │ └── top.v └── game │ ├── arom.v │ ├── display_controller.v │ ├── game.lisp │ ├── game.qpf │ ├── make-sprite-rom.py │ ├── palette.hex │ ├── sprite_detect.v │ ├── sprites.hex │ ├── sprites.txt │ ├── top.qsf │ ├── top.v │ └── vga_timing_generator.v ├── lisp_core.v ├── ram.v ├── rom.v ├── runtime.lisp ├── testbench.v ├── tests ├── anagram.lisp ├── anonfunc.lisp ├── breakloop.lisp ├── closure.lisp ├── compile-fail.lisp ├── conditionals.lisp ├── dict.lisp ├── fib.lisp ├── filter.lisp ├── forloop.lisp ├── gc.lisp ├── gcloop.lisp ├── getbp_bug.lisp ├── hello.lisp ├── list.lisp ├── map-reduce.lisp ├── match-fail.lisp ├── math.lisp ├── oom.lisp ├── optimizer.lisp ├── prime.lisp ├── runtests.py ├── scope.lisp ├── sequence.lisp ├── sum-even-fib.lisp ├── tail-recurse.lisp ├── y-combinator.lisp └── zip.lisp └── ulisp.v /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | workflow_dispatch: 9 | 10 | jobs: 11 | build: 12 | 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - name: Install iverilog 17 | run: sudo apt-get install -y iverilog 18 | - uses: actions/checkout@v1 19 | - name: Run Tests 20 | run: make test 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.hex 2 | *.lst 3 | *.vvp 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2011-2012 Jeff Bush 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | 18 | VERILOG_SRCS = ulisp.v \ 19 | testbench.v \ 20 | rom.v \ 21 | ram.v \ 22 | lisp_core.v 23 | 24 | IVFLAGS=-Wall -Winfloop -Wno-sensitivity-entire-array 25 | 26 | sim.vvp: $(VERILOG_SRCS) 27 | iverilog -o $@ $(IVFLAGS) $(VERILOG_SRCS) 28 | 29 | test: sim.vvp FORCE 30 | python3 tests/runtests.py 31 | 32 | clean: 33 | rm sim.vvp 34 | 35 | FORCE: 36 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![CI](https://github.com/jbush001/LispMicrocontroller/workflows/CI/badge.svg)](https://github.com/jbush001/LispMicrocontroller/actions?query=workflow%3ACI) 2 | [![Codacy Badge](https://api.codacy.com/project/badge/Grade/8f4aff19a2d242f892acc10b98950f46)](https://www.codacy.com/app/jbush001/LispMicrocontroller?utm_source=github.com&utm_medium=referral&utm_content=jbush001/LispMicrocontroller&utm_campaign=Badge_Grade) 3 | 4 | This is a simple microcontroller that runs a compiled LISP dialect. Details of operation are in the [wiki](https://github.com/jbush001/LispMicrocontroller/wiki). 5 | 6 | ## Running in simulation 7 | 8 | This uses Icarus Verilog for simulation (http://iverilog.icarus.com/). Tests are located in the tests/ directory. Run them as follows: 9 | 10 | make test 11 | 12 | The test runner searches files for patterns that begin with 'CHECK:'. The output of the program will be compared to whatever comes after this declaration. If they do not match, an error will be flagged. 13 | 14 | ### Manually running a program 15 | 16 | * Compile the LISP sources. 17 | This produces two files: program.hex, which has the raw program machine code and is loaded by the simulator, and program.lst, which is informational and shows details of the generated code. For example: 18 | 19 | ./compile.py tests/test1.lisp 20 | 21 | Note that any writes to register index 0 will be printed to standard out by the simulation test harness, which is how most simulation tests work. 22 | 23 | * Run simulation. 24 | The simulator will read rom.hex each time it starts. 25 | 26 | vvp sim.vvp 27 | 28 | ## Running in hardware 29 | 30 | This has only been tested under Quartus/Altera with the Cyclone II starter kit. There are a couple of projects located 31 | under the fpga/ directory: 32 | - 7seg: simple program that displays numbers on the 4-digit, 7 segment display 33 | - game: a little arcade-style demo with animated sprites 34 | 35 | ### To build: 36 | 37 | * Compile the LISP sources. 38 | These are located in the project directory, but must be compiled from the top directory. 39 | For example, from LispMicrocontroller/ 40 | 41 | ./compile.py fpga/game/game.lisp 42 | 43 | rom.hex will be created in the top level LispMicrocontroller/ directory. 44 | 45 | * Synthesize the design 46 | Open the program file (for example, fpga/game/game.qpf). Note that the synthesis tools will 47 | read rom.hex to create the values for program ROM. If you recompile the LISP sources (thereby changing rom.hex), the design must be re-synthesized. 48 | 49 | * Run using the programmer included with Quartus. 50 | -------------------------------------------------------------------------------- /fpga/7seg/LispMicrocontroller.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 1991-2011 Altera Corporation 4 | # Your use of Altera Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Altera Program License 10 | # Subscription Agreement, Altera MegaCore Function License 11 | # Agreement, or other applicable license agreement, including, 12 | # without limitation, that your use is for the sole purpose of 13 | # programming logic devices manufactured by Altera and sold by 14 | # Altera or its authorized distributors. Please refer to the 15 | # applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus II 20 | # Version 11.0 Build 208 07/03/2011 Service Pack 1 SJ Web Edition 21 | # Date created = 09:49:39 December 29, 2011 22 | # 23 | # -------------------------------------------------------------------------- # 24 | 25 | QUARTUS_VERSION = "11.0" 26 | DATE = "09:49:39 December 29, 2011" 27 | 28 | # Revisions 29 | 30 | PROJECT_REVISION = "LispMicrocontroller" 31 | -------------------------------------------------------------------------------- /fpga/7seg/LispMicrocontroller.qsf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 1991-2011 Altera Corporation 4 | # Your use of Altera Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Altera Program License 10 | # Subscription Agreement, Altera MegaCore Function License 11 | # Agreement, or other applicable license agreement, including, 12 | # without limitation, that your use is for the sole purpose of 13 | # programming logic devices manufactured by Altera and sold by 14 | # Altera or its authorized distributors. Please refer to the 15 | # applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus II 20 | # Version 11.0 Build 208 07/03/2011 Service Pack 1 SJ Web Edition 21 | # Date created = 09:49:39 December 29, 2011 22 | # 23 | # -------------------------------------------------------------------------- # 24 | # 25 | # Notes: 26 | # 27 | # 1) The default values for assignments are stored in the file: 28 | # LispMicrocontroller_assignment_defaults.qdf 29 | # If this file doesn't exist, see file: 30 | # assignment_defaults.qdf 31 | # 32 | # 2) Altera recommends that you do not modify this file. This 33 | # file is updated automatically by the Quartus II software 34 | # and any changes you make may be lost or overwritten. 35 | # 36 | # -------------------------------------------------------------------------- # 37 | 38 | 39 | set_global_assignment -name FAMILY "Cyclone II" 40 | set_global_assignment -name DEVICE EP2C20F484C7 41 | set_global_assignment -name TOP_LEVEL_ENTITY top 42 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION "11.0 SP1" 43 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "09:49:39 DECEMBER 29, 2011" 44 | set_global_assignment -name LAST_QUARTUS_VERSION "11.0 SP1" 45 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 46 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 47 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1 48 | set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top 49 | set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top 50 | set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top 51 | set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" 52 | set_location_assignment PIN_U18 -to r_led[7] 53 | set_location_assignment PIN_Y18 -to r_led[6] 54 | set_location_assignment PIN_V19 -to r_led[5] 55 | set_location_assignment PIN_T18 -to r_led[4] 56 | set_location_assignment PIN_Y19 -to r_led[3] 57 | set_location_assignment PIN_U19 -to r_led[2] 58 | set_location_assignment PIN_R19 -to r_led[1] 59 | set_location_assignment PIN_R20 -to r_led[0] 60 | set_location_assignment PIN_L1 -to clk50 61 | set_location_assignment PIN_D4 -to digit3[6] 62 | set_location_assignment PIN_F3 -to digit3[5] 63 | set_location_assignment PIN_L8 -to digit3[4] 64 | set_location_assignment PIN_J4 -to digit3[3] 65 | set_location_assignment PIN_D6 -to digit3[2] 66 | set_location_assignment PIN_D5 -to digit3[1] 67 | set_location_assignment PIN_F4 -to digit3[0] 68 | set_location_assignment PIN_D3 -to digit2[6] 69 | set_location_assignment PIN_E4 -to digit2[5] 70 | set_location_assignment PIN_E3 -to digit2[4] 71 | set_location_assignment PIN_C1 -to digit2[3] 72 | set_location_assignment PIN_C2 -to digit2[2] 73 | set_location_assignment PIN_G6 -to digit2[1] 74 | set_location_assignment PIN_G5 -to digit2[0] 75 | set_location_assignment PIN_D1 -to digit1[6] 76 | set_location_assignment PIN_D2 -to digit1[5] 77 | set_location_assignment PIN_G3 -to digit1[4] 78 | set_location_assignment PIN_H4 -to digit1[3] 79 | set_location_assignment PIN_H5 -to digit1[2] 80 | set_location_assignment PIN_H6 -to digit1[1] 81 | set_location_assignment PIN_E1 -to digit1[0] 82 | set_location_assignment PIN_E2 -to digit0[6] 83 | set_location_assignment PIN_F1 -to digit0[5] 84 | set_location_assignment PIN_F2 -to digit0[4] 85 | set_location_assignment PIN_H1 -to digit0[3] 86 | set_location_assignment PIN_H2 -to digit0[2] 87 | set_location_assignment PIN_J1 -to digit0[1] 88 | set_location_assignment PIN_J2 -to digit0[0] 89 | set_location_assignment PIN_T21 -to buttons[3] 90 | set_location_assignment PIN_T22 -to buttons[2] 91 | set_location_assignment PIN_R21 -to buttons[1] 92 | set_location_assignment PIN_R22 -to buttons[0] 93 | 94 | 95 | set_global_assignment -name SYNTH_TIMING_DRIVEN_SYNTHESIS OFF 96 | set_global_assignment -name HDL_MESSAGE_OFF 10222 97 | set_global_assignment -name HDL_MESSAGE_OFF 10850 98 | set_global_assignment -name HDL_MESSAGE_OFF 10230 99 | 100 | 101 | set_global_assignment -name VERILOG_FILE ../../rom.v 102 | set_global_assignment -name VERILOG_FILE ../../ram.v 103 | set_global_assignment -name VERILOG_FILE ../../lisp_core.v 104 | set_global_assignment -name VERILOG_FILE ../../ulisp.v 105 | set_global_assignment -name VERILOG_FILE top.v 106 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /fpga/7seg/blink.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; 18 | ; On Cyclone II dev board, make LEDs flash in sequence. 19 | ; 20 | 21 | (assign a 1) 22 | (while 1 23 | (assign a (bitwise-or (lshift a 1) (rshift a 7))) 24 | (write-register 1 a) 25 | (for j 0 10 1 26 | (for i 0 16000 1 27 | ()))) 28 | 29 | -------------------------------------------------------------------------------- /fpga/7seg/counter.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | 18 | (assign segments '(64 249 36 48 25 18 2 120 0 16)) 19 | 20 | (function set-display (num) 21 | (for register 2 6 1 22 | (begin 23 | (write-register register (nth segments (mod num 10))) 24 | (assign num (/ num 10))))) 25 | 26 | (assign a 0) 27 | (while 1 28 | (set-display a) 29 | (assign a (+ a 1)) 30 | (if (> a 9999) 31 | (assign a 0)) 32 | (for j 0 5 1 33 | (for i 0 16000 1 34 | ()))) 35 | -------------------------------------------------------------------------------- /fpga/7seg/fibonacci.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; 18 | ; On the cyclone II dev board, compute nth iteration of a fibonacci sequence and display 19 | ; on 7 segment display 20 | ; 21 | 22 | (assign segments '(64 249 36 48 25 18 2 120 0 16)) 23 | 24 | (function set-display (num) 25 | (for register 2 6 1 26 | (begin 27 | (write-register register (nth segments (mod num 10))) 28 | (assign num (/ num 10))))) 29 | 30 | (function fib (n) 31 | (if (< n 2) 32 | n 33 | (+ (fib (- n 1)) (fib (- n 2))))) 34 | 35 | (assign a 0) 36 | (while 1 37 | (set-display (fib a)) 38 | (assign a (+ a 1)) 39 | 40 | ; Wait for key release 41 | (while (bitwise-and (read-register 6) 1) 42 | ()) 43 | 44 | ; Wait for key press 45 | (while (= (bitwise-and (read-register 6) 1) 0) 46 | ())) 47 | 48 | -------------------------------------------------------------------------------- /fpga/7seg/top.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | module top( 18 | input clk50, 19 | output reg[7:0] r_led = 0, 20 | output reg[6:0] digit3 = 0, 21 | output reg[6:0] digit2 = 0, 22 | output reg[6:0] digit1 = 0, 23 | output reg[6:0] digit0 = 0, 24 | input [3:0] buttons); 25 | 26 | wire[6:0] register_index; 27 | wire register_read; 28 | wire register_write; 29 | wire[15:0] register_write_value; 30 | reg[15:0] register_read_value = 0; 31 | reg[3:0] buttons_sync0 = 0; 32 | reg[3:0] buttons_sync1 = 0; 33 | reg clk = 0; 34 | reg reset = 1; 35 | reg[3:0] reset_count = 7; 36 | 37 | // Divide 50 Mhz clock down to 25 Mhz 38 | always @(posedge clk50) 39 | clk <= ~clk; 40 | 41 | ulisp l( 42 | .clk(clk), 43 | .reset(reset), 44 | .register_index(register_index), 45 | .register_read(register_read), 46 | .register_write(register_write), 47 | .register_write_value(register_write_value), 48 | .register_read_value(register_read_value)); 49 | 50 | always @(posedge clk) 51 | begin 52 | if (reset_count == 0) 53 | reset <= 0; 54 | else 55 | reset_count <= reset_count - 1; 56 | 57 | if (register_write) 58 | begin 59 | case (register_index) 60 | 1: r_led <= register_write_value[7:0]; 61 | 2: digit0 <= register_write_value[6:0]; 62 | 3: digit1 <= register_write_value[6:0]; 63 | 4: digit2 <= register_write_value[6:0]; 64 | 5: digit3 <= register_write_value[6:0]; 65 | endcase 66 | end 67 | 68 | if (register_read && register_index == 6) 69 | register_read_value <= {12'd0, buttons_sync1 }; 70 | 71 | buttons_sync0 <= buttons; 72 | buttons_sync1 <= buttons_sync0; 73 | end 74 | 75 | endmodule 76 | 77 | -------------------------------------------------------------------------------- /fpga/game/arom.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | // Asynchronous ROM 20 | module arom 21 | #(parameter MEM_SIZE = 4096, 22 | parameter WORD_SIZE = 20, 23 | parameter ADDR_SIZE = 16, 24 | parameter INIT_FILE="") 25 | 26 | (input [ADDR_SIZE - 1:0] addr_i, 27 | output [WORD_SIZE - 1:0] value_o); 28 | 29 | reg[WORD_SIZE - 1:0] data[0:MEM_SIZE]; 30 | 31 | initial 32 | $readmemh(INIT_FILE, data); 33 | 34 | assign value_o = data[addr_i]; 35 | endmodule 36 | -------------------------------------------------------------------------------- /fpga/game/display_controller.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | module display_controller( 18 | input clk, 19 | output hsync_o, 20 | output vsync_o, 21 | output [3:0] red_o, 22 | output [3:0] green_o, 23 | output [3:0] blue_o, 24 | input register_write_i, 25 | input [11:0] register_index_i, 26 | input [15:0] register_write_value_i, 27 | output in_vblank_o, 28 | output reg[5:0] collision_o); 29 | 30 | wire[9:0] raster_x_native; 31 | wire[9:0] raster_y_native; 32 | wire[9:0] raster_x; 33 | wire[9:0] raster_y; 34 | wire in_visible_region; 35 | wire[11:0] sprite0_address; 36 | wire[11:0] sprite1_address; 37 | wire[11:0] sprite2_address; 38 | wire[11:0] sprite3_address; 39 | wire sprite0_active; 40 | wire sprite1_active; 41 | wire sprite2_active; 42 | wire sprite3_active; 43 | 44 | vga_timing_generator vtg( 45 | .clk(clk), 46 | .vsync_o(vsync_o), 47 | .hsync_o(hsync_o), 48 | .in_visible_region(in_visible_region), 49 | .x_coord(raster_x_native), 50 | .y_coord(raster_y_native), 51 | .in_vblank(in_vblank_o)); 52 | 53 | // Cut the resolution by half in each dimension 54 | assign raster_x = { 1'b0, raster_x_native[9:1] }; 55 | assign raster_y = { 1'b0, raster_y_native[9:1] }; 56 | 57 | sprite_detect #(3) sprite0( 58 | .clk(clk), 59 | .raster_x(raster_x), 60 | .raster_y(raster_y), 61 | .register_write_i(register_write_i), 62 | .register_index_i(register_index_i), 63 | .register_write_value_i(register_write_value_i), 64 | .sprite_active(sprite0_active), 65 | .sprite_address(sprite0_address)); 66 | 67 | sprite_detect #(7) sprite1( 68 | .clk(clk), 69 | .raster_x(raster_x), 70 | .raster_y(raster_y), 71 | .register_write_i(register_write_i), 72 | .register_index_i(register_index_i), 73 | .register_write_value_i(register_write_value_i), 74 | .sprite_active(sprite1_active), 75 | .sprite_address(sprite1_address)); 76 | 77 | sprite_detect #(11) sprite2( 78 | .clk(clk), 79 | .raster_x(raster_x), 80 | .raster_y(raster_y), 81 | .register_write_i(register_write_i), 82 | .register_index_i(register_index_i), 83 | .register_write_value_i(register_write_value_i), 84 | .sprite_active(sprite2_active), 85 | .sprite_address(sprite2_address)); 86 | 87 | sprite_detect #(14) sprite3( 88 | .clk(clk), 89 | .raster_x(raster_x), 90 | .raster_y(raster_y), 91 | .register_write_i(register_write_i), 92 | .register_index_i(register_index_i), 93 | .register_write_value_i(register_write_value_i), 94 | .sprite_active(sprite3_active), 95 | .sprite_address(sprite3_address)); 96 | 97 | // Sprite priority logic 98 | reg[11:0] sprite_addr = 0; // Sprite shape + address 99 | always @* 100 | begin 101 | if (sprite0_active) 102 | sprite_addr = sprite0_address; 103 | else if (sprite1_active) 104 | sprite_addr = sprite1_address; 105 | else if (sprite2_active) 106 | sprite_addr = sprite2_address; 107 | else /* sprite3 active or don't care */ 108 | sprite_addr = sprite3_address; 109 | end 110 | 111 | reg[5:0] collision = 0; 112 | reg in_vblank_latched = 0; 113 | 114 | always @(posedge clk) 115 | begin 116 | in_vblank_latched <= in_vblank_o; 117 | 118 | if (in_vblank_o & ~in_vblank_latched) 119 | begin 120 | // Start of frame 121 | collision <= 0; 122 | collision_o <= collision; 123 | end 124 | else 125 | begin 126 | collision <= collision | { 127 | sprite0_active & sprite1_active, 128 | sprite0_active & sprite2_active, 129 | sprite0_active & sprite3_active, 130 | sprite1_active & sprite2_active, 131 | sprite1_active & sprite3_active, 132 | sprite2_active & sprite3_active 133 | }; 134 | end 135 | end 136 | 137 | 138 | wire[11:0] sprite_color; 139 | wire[3:0] sprite_color_index; 140 | 141 | arom #(4096, 4, 12, "sprites.hex") sprite_rom( 142 | .addr_i(sprite_addr), 143 | .value_o(sprite_color_index)); 144 | 145 | arom #(16, 12, 4, "palette.hex") palette_rom( 146 | .addr_i(sprite_color_index), 147 | .value_o(sprite_color)); 148 | 149 | wire sprite_is_active = sprite0_active || sprite1_active; 150 | 151 | reg[11:0] output_color = 0; 152 | assign { red_o, green_o, blue_o } = output_color; 153 | always @* 154 | begin 155 | if (in_visible_region) 156 | begin 157 | if (sprite_is_active && sprite_color_index != 0) 158 | output_color = sprite_color; 159 | else 160 | output_color = 12'b000000000100; // Background color 161 | end 162 | else 163 | output_color = 12'd0; 164 | end 165 | endmodule 166 | -------------------------------------------------------------------------------- /fpga/game/game.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | 18 | (write-register 3 160) 19 | (write-register 6 1) ; enable sprite 0 (player rocket) 20 | (write-register 4 (- 240 30)) ; y coord (a little up from the bottom) 21 | (assign x0 (- 160 8)) 22 | 23 | (while 1 24 | ; Wait for start of vblank 25 | (while (<> (read-register 1) 1) 26 | ()) 27 | 28 | ; Set up sprite 0 29 | (write-register 3 x0) ; X coord 30 | (write-register 5 animationFrame) ; animation frame 31 | 32 | ; Set up missile 33 | (write-register 7 missile-x) 34 | (write-register 8 missile-y) 35 | (write-register 9 (+ 2 animationFrame)) ; animation frame 36 | (write-register 10 missile-active) 37 | 38 | ; Wait for end of vblank 39 | (while (read-register 1) 40 | ()) 41 | 42 | ; Left? 43 | (if (<> (bitwise-and (read-register 0) 1) 0) 44 | (if (> x0 3) 45 | (assign x0 (- x0 3)))) 46 | 47 | ; Move right? 48 | (if (<> (bitwise-and (read-register 0) 2) 0) 49 | (if (< x0 (- 320 (+ 16 3))) 50 | (assign x0 (+ x0 3)))) 51 | 52 | ; Update missile 53 | (if missile-active 54 | ; Missile is active 55 | (begin 56 | (assign missile-y (- missile-y 2)) 57 | (if (< missile-y -16) 58 | (assign missile-active 0))) ; Missile off top of screen 59 | 60 | ; Missile is not active, test for firing 61 | (if (= (bitwise-and (read-register 0) 4) 0) ; Not clear why this is inverted 62 | (begin 63 | (assign missile-active 1) 64 | (assign missile-y (- 240 32)) 65 | (assign missile-x x0)))) 66 | 67 | ; Animate 68 | (if (= animation-delay 0) 69 | ; Animate jet exhaust 70 | (begin 71 | (assign animationFrame (- 1 animationFrame)) 72 | (assign animation-delay 3)) 73 | (assign animation-delay (- animation-delay 1)))) 74 | 75 | 76 | -------------------------------------------------------------------------------- /fpga/game/game.qpf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 1991-2011 Altera Corporation 4 | # Your use of Altera Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Altera Program License 10 | # Subscription Agreement, Altera MegaCore Function License 11 | # Agreement, or other applicable license agreement, including, 12 | # without limitation, that your use is for the sole purpose of 13 | # programming logic devices manufactured by Altera and sold by 14 | # Altera or its authorized distributors. Please refer to the 15 | # applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus II 20 | # Version 11.0 Build 208 07/03/2011 Service Pack 1 SJ Web Edition 21 | # Date created = 14:44:34 March 04, 2012 22 | # 23 | # -------------------------------------------------------------------------- # 24 | 25 | QUARTUS_VERSION = "11.0" 26 | DATE = "14:44:34 March 04, 2012" 27 | 28 | # Revisions 29 | 30 | PROJECT_REVISION = "top" 31 | -------------------------------------------------------------------------------- /fpga/game/make-sprite-rom.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2011-2012 Jeff Bush 3 | # 4 | # Licensed under the Apache License, Version 2.0 (the "License"); 5 | # you may not use this file except in compliance with the License. 6 | # You may obtain a copy of the License at 7 | # 8 | # http://www.apache.org/licenses/LICENSE-2.0 9 | # 10 | # Unless required by applicable law or agreed to in writing, software 11 | # distributed under the License is distributed on an "AS IS" BASIS, 12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | # See the License for the specific language governing permissions and 14 | # limitations under the License. 15 | # 16 | 17 | import sys 18 | 19 | readingPalette = True 20 | inSprite = False 21 | paletteKey = {} 22 | palette = [0 for x in range(16)] 23 | currentSprite = [] 24 | sprites = [] 25 | 26 | for line in open(sys.argv[1]): 27 | if not line.strip(): 28 | # Empty line 29 | readingPalette = False 30 | if inSprite: 31 | sprites += [ currentSprite ] 32 | currentSprite = [] 33 | inSprite = False 34 | else: 35 | if readingPalette: 36 | ch, r, g, b = line.split() 37 | palette[len(paletteKey)] = ((int(r) & 15) << 8) | ((int(g) & 15) << 4) | (int(b) & 15) 38 | paletteKey[ch] = len(paletteKey) 39 | else: 40 | inSprite = True 41 | for ch in line.strip(): 42 | currentSprite += [ paletteKey[ch] ] 43 | 44 | if inSprite: 45 | sprites += [ currentSprite ] 46 | 47 | # Write the palette file 48 | f = open('palette.hex', 'w') 49 | for x in palette: 50 | f.write('%03x\n' % x) 51 | 52 | f.close() 53 | 54 | # Write the sprites file 55 | f = open('sprites.hex', 'w') 56 | for sp in sprites: 57 | for val in sp: 58 | f.write('%x\n' % val) 59 | 60 | f.close() 61 | -------------------------------------------------------------------------------- /fpga/game/palette.hex: -------------------------------------------------------------------------------- 1 | 000 2 | f00 3 | 0f0 4 | 00f 5 | ff0 6 | f08 7 | 000 8 | 000 9 | 000 10 | 000 11 | 000 12 | 000 13 | 000 14 | 000 15 | 000 16 | 000 17 | -------------------------------------------------------------------------------- /fpga/game/sprite_detect.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | // Sprites are 16x16 pixels 18 | 19 | module sprite_detect 20 | #(parameter BASE_INDEX = 0) 21 | (input clk, 22 | input [9:0] raster_x, 23 | input [9:0] raster_y, 24 | input register_write_i, 25 | input [11:0] register_index_i, 26 | input [15:0] register_write_value_i, 27 | output sprite_active, 28 | output [11:0] sprite_address); 29 | 30 | reg[9:0] sprite_x = 0; 31 | reg[9:0] sprite_y = 0; 32 | reg[3:0] sprite_shape = 0; 33 | reg sprite_enable = 0; 34 | 35 | wire[9:0] sprite_x_offset = raster_x - sprite_x; 36 | wire[9:0] sprite_y_offset = raster_y - sprite_y; 37 | assign sprite_active = sprite_enable && sprite_x_offset[9:4] == 0 && sprite_y_offset[9:4] == 0; 38 | assign sprite_address = { sprite_shape, sprite_y_offset[3:0], sprite_x_offset[3:0] }; 39 | 40 | always @(posedge clk) 41 | begin 42 | if (register_write_i) 43 | begin 44 | case (register_index_i) 45 | BASE_INDEX: sprite_x <= register_write_value_i[9:0]; 46 | BASE_INDEX + 1: sprite_y <= register_write_value_i[9:0]; 47 | BASE_INDEX + 2: sprite_shape <= register_write_value_i[3:0]; 48 | BASE_INDEX + 3: sprite_enable <= register_write_value_i != 0; 49 | endcase 50 | end 51 | end 52 | endmodule 53 | -------------------------------------------------------------------------------- /fpga/game/sprites.hex: -------------------------------------------------------------------------------- 1 | 0 2 | 0 3 | 0 4 | 0 5 | 0 6 | 0 7 | 0 8 | 0 9 | 0 10 | 0 11 | 0 12 | 0 13 | 0 14 | 0 15 | 0 16 | 0 17 | 0 18 | 0 19 | 0 20 | 0 21 | 0 22 | 0 23 | 0 24 | 1 25 | 1 26 | 0 27 | 0 28 | 0 29 | 0 30 | 0 31 | 0 32 | 0 33 | 0 34 | 0 35 | 0 36 | 0 37 | 0 38 | 0 39 | 1 40 | 1 41 | 1 42 | 1 43 | 0 44 | 0 45 | 0 46 | 0 47 | 0 48 | 0 49 | 0 50 | 0 51 | 0 52 | 0 53 | 0 54 | 1 55 | 1 56 | 3 57 | 3 58 | 1 59 | 1 60 | 0 61 | 0 62 | 0 63 | 0 64 | 0 65 | 0 66 | 1 67 | 0 68 | 0 69 | 1 70 | 1 71 | 3 72 | 3 73 | 3 74 | 3 75 | 1 76 | 1 77 | 0 78 | 0 79 | 1 80 | 0 81 | 0 82 | 1 83 | 0 84 | 0 85 | 1 86 | 1 87 | 3 88 | 3 89 | 3 90 | 3 91 | 1 92 | 1 93 | 0 94 | 0 95 | 1 96 | 0 97 | 0 98 | 1 99 | 0 100 | 0 101 | 1 102 | 1 103 | 3 104 | 3 105 | 3 106 | 3 107 | 1 108 | 1 109 | 0 110 | 0 111 | 1 112 | 0 113 | 0 114 | 1 115 | 0 116 | 0 117 | 1 118 | 1 119 | 1 120 | 3 121 | 3 122 | 1 123 | 1 124 | 1 125 | 0 126 | 0 127 | 1 128 | 0 129 | 0 130 | 1 131 | 0 132 | 1 133 | 1 134 | 1 135 | 1 136 | 1 137 | 1 138 | 1 139 | 1 140 | 1 141 | 1 142 | 0 143 | 1 144 | 0 145 | 0 146 | 1 147 | 1 148 | 1 149 | 1 150 | 1 151 | 1 152 | 1 153 | 1 154 | 1 155 | 1 156 | 1 157 | 1 158 | 1 159 | 1 160 | 0 161 | 0 162 | 1 163 | 1 164 | 1 165 | 0 166 | 1 167 | 1 168 | 1 169 | 1 170 | 1 171 | 1 172 | 0 173 | 1 174 | 1 175 | 1 176 | 0 177 | 0 178 | 1 179 | 1 180 | 0 181 | 0 182 | 0 183 | 1 184 | 1 185 | 1 186 | 1 187 | 0 188 | 0 189 | 0 190 | 1 191 | 1 192 | 0 193 | 0 194 | 1 195 | 0 196 | 0 197 | 0 198 | 0 199 | 0 200 | 1 201 | 1 202 | 0 203 | 0 204 | 0 205 | 0 206 | 0 207 | 1 208 | 0 209 | 0 210 | 0 211 | 0 212 | 0 213 | 0 214 | 0 215 | 0 216 | 5 217 | 4 218 | 0 219 | 0 220 | 0 221 | 0 222 | 0 223 | 0 224 | 0 225 | 0 226 | 0 227 | 0 228 | 0 229 | 0 230 | 0 231 | 5 232 | 0 233 | 4 234 | 4 235 | 0 236 | 0 237 | 0 238 | 0 239 | 0 240 | 0 241 | 0 242 | 0 243 | 0 244 | 0 245 | 0 246 | 4 247 | 0 248 | 0 249 | 4 250 | 0 251 | 0 252 | 0 253 | 0 254 | 0 255 | 0 256 | 0 257 | 0 258 | 0 259 | 0 260 | 0 261 | 0 262 | 0 263 | 0 264 | 0 265 | 0 266 | 0 267 | 0 268 | 0 269 | 0 270 | 0 271 | 0 272 | 0 273 | 0 274 | 0 275 | 0 276 | 0 277 | 0 278 | 0 279 | 0 280 | 1 281 | 1 282 | 0 283 | 0 284 | 0 285 | 0 286 | 0 287 | 0 288 | 0 289 | 0 290 | 0 291 | 0 292 | 0 293 | 0 294 | 0 295 | 1 296 | 1 297 | 1 298 | 1 299 | 0 300 | 0 301 | 0 302 | 0 303 | 0 304 | 0 305 | 0 306 | 0 307 | 0 308 | 0 309 | 0 310 | 1 311 | 1 312 | 3 313 | 3 314 | 1 315 | 1 316 | 0 317 | 0 318 | 0 319 | 0 320 | 0 321 | 0 322 | 1 323 | 0 324 | 0 325 | 1 326 | 1 327 | 3 328 | 3 329 | 3 330 | 3 331 | 1 332 | 1 333 | 0 334 | 0 335 | 1 336 | 0 337 | 0 338 | 1 339 | 0 340 | 0 341 | 1 342 | 1 343 | 3 344 | 3 345 | 3 346 | 3 347 | 1 348 | 1 349 | 0 350 | 0 351 | 1 352 | 0 353 | 0 354 | 1 355 | 0 356 | 0 357 | 1 358 | 1 359 | 3 360 | 3 361 | 3 362 | 3 363 | 1 364 | 1 365 | 0 366 | 0 367 | 1 368 | 0 369 | 0 370 | 1 371 | 0 372 | 0 373 | 1 374 | 1 375 | 1 376 | 3 377 | 3 378 | 1 379 | 1 380 | 1 381 | 0 382 | 0 383 | 1 384 | 0 385 | 0 386 | 1 387 | 0 388 | 1 389 | 1 390 | 1 391 | 1 392 | 1 393 | 1 394 | 1 395 | 1 396 | 1 397 | 1 398 | 0 399 | 1 400 | 0 401 | 0 402 | 1 403 | 1 404 | 1 405 | 1 406 | 1 407 | 1 408 | 1 409 | 1 410 | 1 411 | 1 412 | 1 413 | 1 414 | 1 415 | 1 416 | 0 417 | 0 418 | 1 419 | 1 420 | 1 421 | 0 422 | 1 423 | 1 424 | 1 425 | 1 426 | 1 427 | 1 428 | 0 429 | 1 430 | 1 431 | 1 432 | 0 433 | 0 434 | 1 435 | 1 436 | 0 437 | 0 438 | 0 439 | 1 440 | 1 441 | 1 442 | 1 443 | 0 444 | 0 445 | 0 446 | 1 447 | 1 448 | 0 449 | 0 450 | 1 451 | 0 452 | 0 453 | 0 454 | 0 455 | 0 456 | 1 457 | 1 458 | 0 459 | 0 460 | 0 461 | 0 462 | 0 463 | 1 464 | 0 465 | 0 466 | 0 467 | 0 468 | 0 469 | 0 470 | 0 471 | 0 472 | 4 473 | 5 474 | 0 475 | 0 476 | 0 477 | 0 478 | 0 479 | 0 480 | 0 481 | 0 482 | 0 483 | 0 484 | 0 485 | 0 486 | 0 487 | 5 488 | 0 489 | 4 490 | 0 491 | 0 492 | 0 493 | 0 494 | 0 495 | 0 496 | 0 497 | 0 498 | 0 499 | 0 500 | 0 501 | 0 502 | 0 503 | 4 504 | 0 505 | 5 506 | 0 507 | 5 508 | 0 509 | 0 510 | 0 511 | 0 512 | 0 513 | 0 514 | 0 515 | 0 516 | 0 517 | 0 518 | 0 519 | 0 520 | 3 521 | 3 522 | 0 523 | 0 524 | 0 525 | 0 526 | 0 527 | 0 528 | 0 529 | 0 530 | 0 531 | 0 532 | 0 533 | 0 534 | 0 535 | 3 536 | 3 537 | 3 538 | 3 539 | 0 540 | 0 541 | 0 542 | 0 543 | 0 544 | 0 545 | 0 546 | 0 547 | 0 548 | 0 549 | 0 550 | 0 551 | 3 552 | 3 553 | 3 554 | 3 555 | 0 556 | 0 557 | 0 558 | 0 559 | 0 560 | 0 561 | 0 562 | 0 563 | 0 564 | 0 565 | 0 566 | 0 567 | 3 568 | 3 569 | 3 570 | 3 571 | 0 572 | 0 573 | 0 574 | 0 575 | 0 576 | 0 577 | 0 578 | 0 579 | 0 580 | 0 581 | 0 582 | 0 583 | 3 584 | 3 585 | 3 586 | 3 587 | 0 588 | 0 589 | 0 590 | 0 591 | 0 592 | 0 593 | 0 594 | 0 595 | 0 596 | 0 597 | 0 598 | 0 599 | 3 600 | 3 601 | 3 602 | 3 603 | 0 604 | 0 605 | 0 606 | 0 607 | 0 608 | 0 609 | 0 610 | 0 611 | 0 612 | 0 613 | 0 614 | 0 615 | 3 616 | 3 617 | 3 618 | 3 619 | 0 620 | 0 621 | 0 622 | 0 623 | 0 624 | 0 625 | 0 626 | 0 627 | 0 628 | 0 629 | 0 630 | 0 631 | 3 632 | 3 633 | 3 634 | 3 635 | 0 636 | 0 637 | 0 638 | 0 639 | 0 640 | 0 641 | 0 642 | 0 643 | 0 644 | 0 645 | 0 646 | 0 647 | 3 648 | 3 649 | 3 650 | 3 651 | 0 652 | 0 653 | 0 654 | 0 655 | 0 656 | 0 657 | 0 658 | 0 659 | 0 660 | 0 661 | 0 662 | 0 663 | 3 664 | 3 665 | 3 666 | 3 667 | 0 668 | 0 669 | 0 670 | 0 671 | 0 672 | 0 673 | 0 674 | 0 675 | 0 676 | 0 677 | 0 678 | 3 679 | 3 680 | 3 681 | 3 682 | 3 683 | 3 684 | 0 685 | 0 686 | 0 687 | 0 688 | 0 689 | 0 690 | 0 691 | 0 692 | 0 693 | 3 694 | 3 695 | 3 696 | 3 697 | 3 698 | 3 699 | 3 700 | 3 701 | 0 702 | 0 703 | 0 704 | 0 705 | 0 706 | 0 707 | 0 708 | 3 709 | 3 710 | 3 711 | 3 712 | 3 713 | 3 714 | 3 715 | 3 716 | 3 717 | 3 718 | 0 719 | 0 720 | 0 721 | 0 722 | 0 723 | 0 724 | 0 725 | 0 726 | 0 727 | 0 728 | 5 729 | 1 730 | 0 731 | 0 732 | 0 733 | 0 734 | 0 735 | 0 736 | 0 737 | 0 738 | 0 739 | 0 740 | 0 741 | 0 742 | 0 743 | 1 744 | 0 745 | 5 746 | 0 747 | 1 748 | 0 749 | 0 750 | 0 751 | 0 752 | 0 753 | 0 754 | 0 755 | 0 756 | 0 757 | 0 758 | 0 759 | 0 760 | 1 761 | 0 762 | 5 763 | 0 764 | 0 765 | 0 766 | 0 767 | 0 768 | 0 769 | 0 770 | 0 771 | 0 772 | 0 773 | 0 774 | 0 775 | 0 776 | 3 777 | 3 778 | 0 779 | 0 780 | 0 781 | 0 782 | 0 783 | 0 784 | 0 785 | 0 786 | 0 787 | 0 788 | 0 789 | 0 790 | 0 791 | 3 792 | 3 793 | 3 794 | 3 795 | 0 796 | 0 797 | 0 798 | 0 799 | 0 800 | 0 801 | 0 802 | 0 803 | 0 804 | 0 805 | 0 806 | 0 807 | 3 808 | 3 809 | 3 810 | 3 811 | 0 812 | 0 813 | 0 814 | 0 815 | 0 816 | 0 817 | 0 818 | 0 819 | 0 820 | 0 821 | 0 822 | 0 823 | 3 824 | 3 825 | 3 826 | 3 827 | 0 828 | 0 829 | 0 830 | 0 831 | 0 832 | 0 833 | 0 834 | 0 835 | 0 836 | 0 837 | 0 838 | 0 839 | 3 840 | 3 841 | 3 842 | 3 843 | 0 844 | 0 845 | 0 846 | 0 847 | 0 848 | 0 849 | 0 850 | 0 851 | 0 852 | 0 853 | 0 854 | 0 855 | 3 856 | 3 857 | 3 858 | 3 859 | 0 860 | 0 861 | 0 862 | 0 863 | 0 864 | 0 865 | 0 866 | 0 867 | 0 868 | 0 869 | 0 870 | 0 871 | 3 872 | 3 873 | 3 874 | 3 875 | 0 876 | 0 877 | 0 878 | 0 879 | 0 880 | 0 881 | 0 882 | 0 883 | 0 884 | 0 885 | 0 886 | 0 887 | 3 888 | 3 889 | 3 890 | 3 891 | 0 892 | 0 893 | 0 894 | 0 895 | 0 896 | 0 897 | 0 898 | 0 899 | 0 900 | 0 901 | 0 902 | 0 903 | 3 904 | 3 905 | 3 906 | 3 907 | 0 908 | 0 909 | 0 910 | 0 911 | 0 912 | 0 913 | 0 914 | 0 915 | 0 916 | 0 917 | 0 918 | 0 919 | 3 920 | 3 921 | 3 922 | 3 923 | 0 924 | 0 925 | 0 926 | 0 927 | 0 928 | 0 929 | 0 930 | 0 931 | 0 932 | 0 933 | 0 934 | 3 935 | 3 936 | 3 937 | 3 938 | 3 939 | 3 940 | 0 941 | 0 942 | 0 943 | 0 944 | 0 945 | 0 946 | 0 947 | 0 948 | 0 949 | 3 950 | 3 951 | 3 952 | 3 953 | 3 954 | 3 955 | 3 956 | 3 957 | 0 958 | 0 959 | 0 960 | 0 961 | 0 962 | 0 963 | 0 964 | 3 965 | 3 966 | 3 967 | 3 968 | 3 969 | 3 970 | 3 971 | 3 972 | 3 973 | 3 974 | 0 975 | 0 976 | 0 977 | 0 978 | 0 979 | 0 980 | 0 981 | 0 982 | 0 983 | 0 984 | 5 985 | 1 986 | 0 987 | 0 988 | 0 989 | 0 990 | 0 991 | 0 992 | 0 993 | 0 994 | 0 995 | 0 996 | 0 997 | 0 998 | 0 999 | 5 1000 | 1 1001 | 5 1002 | 0 1003 | 0 1004 | 0 1005 | 0 1006 | 0 1007 | 0 1008 | 0 1009 | 0 1010 | 0 1011 | 0 1012 | 0 1013 | 1 1014 | 0 1015 | 0 1016 | 1 1017 | 0 1018 | 5 1019 | 0 1020 | 0 1021 | 0 1022 | 0 1023 | 0 1024 | 0 1025 | -------------------------------------------------------------------------------- /fpga/game/sprites.txt: -------------------------------------------------------------------------------- 1 | . 0 0 0 2 | r 15 0 0 3 | g 0 15 0 4 | b 0 0 15 5 | y 15 15 0 6 | o 15 0 8 7 | 8 | ................ 9 | .......rr....... 10 | ......rrrr...... 11 | .....rrbbrr..... 12 | .r..rrbbbbrr..r. 13 | .r..rrbbbbrr..r. 14 | .r..rrbbbbrr..r. 15 | .r..rrrbbrrr..r. 16 | .r.rrrrrrrrrr.r. 17 | .rrrrrrrrrrrrrr. 18 | .rrr.rrrrrr.rrr. 19 | .rr...rrrr...rr. 20 | .r.....rr.....r. 21 | .......oy....... 22 | ......o.yy...... 23 | .....y..y....... 24 | 25 | ................ 26 | .......rr....... 27 | ......rrrr...... 28 | .....rrbbrr..... 29 | .r..rrbbbbrr..r. 30 | .r..rrbbbbrr..r. 31 | .r..rrbbbbrr..r. 32 | .r..rrrbbrrr..r. 33 | .r.rrrrrrrrrr.r. 34 | .rrrrrrrrrrrrrr. 35 | .rrr.rrrrrr.rrr. 36 | .rr...rrrr...rr. 37 | .r.....rr.....r. 38 | .......yo....... 39 | ......o.y....... 40 | ......y.o.o..... 41 | 42 | .......bb....... 43 | ......bbbb...... 44 | ......bbbb...... 45 | ......bbbb...... 46 | ......bbbb...... 47 | ......bbbb...... 48 | ......bbbb...... 49 | ......bbbb...... 50 | ......bbbb...... 51 | ......bbbb...... 52 | .....bbbbbb..... 53 | ....bbbbbbbb.... 54 | ...bbbbbbbbbb... 55 | .......or....... 56 | ......r.o.r..... 57 | .......r.o...... 58 | 59 | 60 | .......bb....... 61 | ......bbbb...... 62 | ......bbbb...... 63 | ......bbbb...... 64 | ......bbbb...... 65 | ......bbbb...... 66 | ......bbbb...... 67 | ......bbbb...... 68 | ......bbbb...... 69 | ......bbbb...... 70 | .....bbbbbb..... 71 | ....bbbbbbbb.... 72 | ...bbbbbbbbbb... 73 | .......or....... 74 | ......oro....... 75 | ....r..r.o...... 76 | 77 | -------------------------------------------------------------------------------- /fpga/game/top.qsf: -------------------------------------------------------------------------------- 1 | # -------------------------------------------------------------------------- # 2 | # 3 | # Copyright (C) 1991-2011 Altera Corporation 4 | # Your use of Altera Corporation's design tools, logic functions 5 | # and other software and tools, and its AMPP partner logic 6 | # functions, and any output files from any of the foregoing 7 | # (including device programming or simulation files), and any 8 | # associated documentation or information are expressly subject 9 | # to the terms and conditions of the Altera Program License 10 | # Subscription Agreement, Altera MegaCore Function License 11 | # Agreement, or other applicable license agreement, including, 12 | # without limitation, that your use is for the sole purpose of 13 | # programming logic devices manufactured by Altera and sold by 14 | # Altera or its authorized distributors. Please refer to the 15 | # applicable agreement for further details. 16 | # 17 | # -------------------------------------------------------------------------- # 18 | # 19 | # Quartus II 20 | # Version 11.0 Build 208 07/03/2011 Service Pack 1 SJ Web Edition 21 | # Date created = 14:44:34 March 04, 2012 22 | # 23 | # -------------------------------------------------------------------------- # 24 | # 25 | # Notes: 26 | # 27 | # 1) The default values for assignments are stored in the file: 28 | # top_assignment_defaults.qdf 29 | # If this file doesn't exist, see file: 30 | # assignment_defaults.qdf 31 | # 32 | # 2) Altera recommends that you do not modify this file. This 33 | # file is updated automatically by the Quartus II software 34 | # and any changes you make may be lost or overwritten. 35 | # 36 | # -------------------------------------------------------------------------- # 37 | 38 | 39 | set_global_assignment -name FAMILY "Cyclone II" 40 | set_global_assignment -name DEVICE EP2C20F484C7 41 | set_global_assignment -name TOP_LEVEL_ENTITY top 42 | set_global_assignment -name ORIGINAL_QUARTUS_VERSION "11.0 SP1" 43 | set_global_assignment -name PROJECT_CREATION_TIME_DATE "14:44:34 MARCH 04, 2012" 44 | set_global_assignment -name LAST_QUARTUS_VERSION "11.0 SP1" 45 | set_global_assignment -name MIN_CORE_JUNCTION_TEMP 0 46 | set_global_assignment -name MAX_CORE_JUNCTION_TEMP 85 47 | set_global_assignment -name ERROR_CHECK_FREQUENCY_DIVISOR 1 48 | set_global_assignment -name STRATIX_DEVICE_IO_STANDARD "3.3-V LVTTL" 49 | set_global_assignment -name PARTITION_NETLIST_TYPE SOURCE -section_id Top 50 | set_global_assignment -name PARTITION_FITTER_PRESERVATION_LEVEL PLACEMENT_AND_ROUTING -section_id Top 51 | set_global_assignment -name PARTITION_COLOR 16764057 -section_id Top 52 | set_location_assignment PIN_L1 -to clk50 53 | set_location_assignment PIN_B10 -to blue_o[3] 54 | set_location_assignment PIN_A10 -to blue_o[2] 55 | set_location_assignment PIN_D11 -to blue_o[1] 56 | set_location_assignment PIN_A9 -to blue_o[0] 57 | set_location_assignment PIN_A8 -to green_o[3] 58 | set_location_assignment PIN_B9 -to green_o[2] 59 | set_location_assignment PIN_C10 -to green_o[1] 60 | set_location_assignment PIN_B8 -to green_o[0] 61 | set_location_assignment PIN_A11 -to hsync_o 62 | set_location_assignment PIN_B7 -to red_o[3] 63 | set_location_assignment PIN_A7 -to red_o[2] 64 | set_location_assignment PIN_C9 -to red_o[1] 65 | set_location_assignment PIN_D9 -to red_o[0] 66 | set_location_assignment PIN_B11 -to vsync_o 67 | set_location_assignment PIN_R22 -to buttons[0] 68 | set_location_assignment PIN_R21 -to buttons[1] 69 | set_location_assignment PIN_T22 -to buttons[2] 70 | set_location_assignment PIN_T21 -to buttons[3] 71 | set_global_assignment -name VERILOG_FILE ../../ulisp.v 72 | set_global_assignment -name VERILOG_FILE ../../rom.v 73 | set_global_assignment -name VERILOG_FILE ../../ram.v 74 | set_global_assignment -name VERILOG_FILE ../../lisp_core.v 75 | set_global_assignment -name VERILOG_FILE vga_timing_generator.v 76 | set_global_assignment -name VERILOG_FILE top.v 77 | set_global_assignment -name VERILOG_FILE sprite_detect.v 78 | set_global_assignment -name VERILOG_FILE display_controller.v 79 | set_global_assignment -name VERILOG_FILE arom.v 80 | set_instance_assignment -name PARTITION_HIERARCHY root_partition -to | -section_id Top -------------------------------------------------------------------------------- /fpga/game/top.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | module top( 18 | input clk50, 19 | output hsync_o, 20 | output vsync_o, 21 | output [3:0] red_o, 22 | output [3:0] green_o, 23 | output [3:0] blue_o, 24 | input [3:0] buttons); 25 | 26 | wire[11:0] register_index; 27 | wire register_read; 28 | wire register_write; 29 | wire[15:0] register_write_value; 30 | reg[15:0] register_read_value = 0; 31 | reg[3:0] buttons_sync0 = 0; 32 | reg[3:0] buttons_sync1 = 0; 33 | reg clk = 0; 34 | wire[5:0] collision; 35 | wire in_vblank; 36 | reg reset = 1; 37 | reg[3:0] reset_count = 7; 38 | 39 | // Divide 50 Mhz clock down to 25 Mhz 40 | always @(posedge clk50) 41 | clk <= ~clk; 42 | 43 | ulisp l( 44 | .clk(clk), 45 | .reset(reset), 46 | .register_index(register_index), 47 | .register_read(register_read), 48 | .register_write(register_write), 49 | .register_write_value(register_write_value), 50 | .register_read_value(register_read_value)); 51 | 52 | display_controller dc( 53 | .clk(clk), 54 | .hsync_o(hsync_o), 55 | .vsync_o(vsync_o), 56 | .red_o(red_o), 57 | .green_o(green_o), 58 | .blue_o(blue_o), 59 | .register_write_i(register_write), 60 | .register_index_i(register_index), 61 | .register_write_value_i(register_write_value), 62 | .in_vblank_o(in_vblank), 63 | .collision_o(collision)); 64 | 65 | always @(posedge clk) 66 | begin 67 | if (reset_count == 0) 68 | reset <= 0; 69 | else 70 | reset_count <= reset_count - 1; 71 | 72 | if (register_read) 73 | begin 74 | case (register_index) 75 | 0: register_read_value <= { 12'd0, buttons_sync1 }; 76 | 1: register_read_value <= in_vblank; 77 | 2: register_read_value <= { 10'd0, collision }; 78 | endcase 79 | end 80 | 81 | buttons_sync0 <= buttons; 82 | buttons_sync1 <= buttons_sync0; 83 | end 84 | 85 | endmodule 86 | 87 | -------------------------------------------------------------------------------- /fpga/game/vga_timing_generator.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | // 18 | // Incoming clock is 25 Mhz 19 | // 20 | 21 | module vga_timing_generator( 22 | input clk, 23 | output reg vsync_o = 0, 24 | output reg hsync_o = 0, 25 | output in_visible_region, 26 | output [9:0] x_coord, 27 | output [9:0] y_coord, 28 | output in_vblank); 29 | 30 | // 640x480 @60 hz. Pixel clock = 25 Mhz (~40 ns) 31 | // Horizontal timing: 32 | // front porch 16 clocks (0.6 uS) 33 | // sync pulse 96 clocks (3.8 uS) 34 | // back porch 48 clocks (1.9 uS) 35 | // visible area 640 clocks 36 | // total 800 clocks 37 | // 38 | // Vertical timing: 39 | // front porch 10 lines 40 | // sync pulse 2 lines 41 | // back porch 33 lines 42 | // visible area 480 lines 43 | // total 525 lines 44 | parameter HSYNC_START = 16; // Front Porch 45 | parameter HSYNC_END = HSYNC_START + 96; 46 | parameter HVISIBLE_START = HSYNC_END + 48; // Back Porch 47 | parameter HVISIBLE_END = HVISIBLE_START + 640; 48 | parameter VSYNC_START = 10; // Front Porch 49 | parameter VSYNC_END = VSYNC_START + 2; 50 | parameter VVISIBLE_START = VSYNC_END + 33; // Back Porch 51 | parameter VVISIBLE_END = VVISIBLE_START + 480; 52 | 53 | reg hvisible = 0; 54 | reg vvisible = 0; 55 | reg[9:0] horizontal_counter = 0; 56 | reg[9:0] vertical_counter = 0; 57 | assign in_visible_region = hvisible && vvisible; 58 | assign in_vblank = !vvisible; 59 | wire hvisible_end = horizontal_counter == HVISIBLE_END; 60 | wire vvisible_end = vertical_counter == VVISIBLE_END; 61 | 62 | assign x_coord = horizontal_counter - HVISIBLE_START; 63 | assign y_coord = vertical_counter - VVISIBLE_START; 64 | 65 | always @(posedge clk) 66 | begin 67 | // Counters 68 | if (hvisible_end) 69 | begin 70 | horizontal_counter <= 0; 71 | hvisible <= 0; 72 | if (vvisible_end) 73 | begin 74 | vvisible <= 0; 75 | vertical_counter <= 0; 76 | end 77 | else 78 | vertical_counter <= vertical_counter + 1; 79 | end 80 | else 81 | horizontal_counter <= horizontal_counter + 1; 82 | 83 | if (vertical_counter == VSYNC_START) 84 | vsync_o <= 0; 85 | else if (vertical_counter == VSYNC_END) 86 | vsync_o <= 1; 87 | else if (vertical_counter == VVISIBLE_START) 88 | vvisible <= 1; 89 | 90 | if (horizontal_counter == HSYNC_START) 91 | hsync_o <= 0; 92 | else if (horizontal_counter == HSYNC_END) 93 | hsync_o <= 1; 94 | else if (horizontal_counter == HVISIBLE_START) 95 | hvisible <= 1; 96 | end 97 | endmodule 98 | -------------------------------------------------------------------------------- /lisp_core.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | module lisp_core 20 | #(parameter DATA_MEM_SIZE = 8192) 21 | 22 | (input clk, 23 | input reset, 24 | 25 | output [15:0] instr_mem_address, 26 | input [20:0] instr_mem_read_value, 27 | output reg[15:0] data_mem_address, 28 | input [18:0] data_mem_read_value, 29 | output reg[18:0] data_mem_write_value, 30 | output reg data_mem_write_enable); 31 | 32 | localparam STATE_DECODE = 0; 33 | localparam STATE_GOT_NOS = 1; 34 | localparam STATE_PUSH_MEM_RESULT = 2; 35 | localparam STATE_GETLOCAL2 = 3; 36 | localparam STATE_RETURN2 = 4; 37 | localparam STATE_RETURN3 = 5; 38 | localparam STATE_GOT_STORE_VALUE = 6; 39 | localparam STATE_GOT_NEW_TAG = 7; 40 | localparam STATE_BFALSE2 = 8; 41 | 42 | localparam OP_NOP = 5'd0; 43 | localparam OP_CALL = 5'd1; 44 | localparam OP_RETURN = 5'd2; 45 | localparam OP_POP = 5'd3; 46 | localparam OP_LOAD = 5'd4; 47 | localparam OP_STORE = 5'd5; 48 | localparam OP_ADD = 5'd6; 49 | localparam OP_SUB = 5'd7; 50 | localparam OP_REST = 5'd8; 51 | localparam OP_GTR = 5'd9; 52 | localparam OP_GTE = 5'd10; 53 | localparam OP_EQ = 5'd11; 54 | localparam OP_NEQ = 5'd12; 55 | localparam OP_DUP = 5'd13; 56 | localparam OP_GETTAG = 5'd14; 57 | localparam OP_SETTAG = 5'd15; 58 | localparam OP_AND = 5'd16; 59 | localparam OP_OR = 5'd17; 60 | localparam OP_XOR = 5'd18; 61 | localparam OP_LSHIFT = 5'd19; 62 | localparam OP_RSHIFT = 5'd20; 63 | localparam OP_GETBP = 5'd21; 64 | localparam OP_RESERVE = 5'd24; 65 | localparam OP_PUSH = 5'd25; 66 | localparam OP_GOTO = 5'd26; 67 | localparam OP_BFALSE = 5'd27; 68 | localparam OP_GETLOCAL = 5'd29; 69 | localparam OP_SETLOCAL = 5'd30; 70 | localparam OP_CLEANUP = 5'd31; 71 | 72 | reg[3:0] state; 73 | reg[18:0] top_of_stack; 74 | reg[15:0] stack_pointer; 75 | reg[15:0] frame_pointer; 76 | reg[15:0] instruction_pointer; 77 | 78 | // 79 | // Instruction fields 80 | // 81 | wire[4:0] opcode = instr_mem_read_value[20:16]; 82 | wire[15:0] param = instr_mem_read_value[15:0]; 83 | 84 | // 85 | // Stack pointer next mux 86 | // 87 | localparam SP_CURRENT = 0; 88 | localparam SP_DECREMENT = 1; 89 | localparam SP_INCREMENT = 2; 90 | localparam SP_ALU = 3; 91 | 92 | reg[1:0] stack_pointer_select = SP_CURRENT; 93 | reg[15:0] stack_pointer_next; 94 | 95 | always @* 96 | begin 97 | case (stack_pointer_select) 98 | SP_CURRENT: stack_pointer_next = stack_pointer; 99 | SP_DECREMENT: stack_pointer_next = stack_pointer - 16'd1; 100 | SP_INCREMENT: stack_pointer_next = stack_pointer + 16'd1; 101 | SP_ALU: stack_pointer_next = alu_result[15:0]; 102 | endcase 103 | end 104 | 105 | // 106 | // ALU op0 mux 107 | // 108 | localparam OP0_TOP_OF_STACK = 0; 109 | localparam OP0_STACK_POINTER = 1; 110 | localparam OP0_FRAME_POINTER = 2; 111 | 112 | reg[1:0] alu_op0_select = OP0_TOP_OF_STACK; 113 | reg[15:0] alu_op0; 114 | 115 | always @* 116 | begin 117 | case (alu_op0_select) 118 | OP0_TOP_OF_STACK: alu_op0 = top_of_stack[15:0]; 119 | OP0_STACK_POINTER: alu_op0 = stack_pointer; 120 | OP0_FRAME_POINTER: alu_op0 = frame_pointer; 121 | default: alu_op0 = {16{1'bx}}; 122 | endcase 123 | end 124 | 125 | // 126 | // ALU op1 mux 127 | // 128 | localparam OP1_MEM_READ = 0; 129 | localparam OP1_PARAM = 1; 130 | localparam OP1_ONE = 2; 131 | 132 | reg[1:0] alu_op1_select = OP1_MEM_READ; 133 | reg[15:0] alu_op1; 134 | 135 | always @* 136 | begin 137 | case (alu_op1_select) 138 | OP1_MEM_READ: alu_op1 = data_mem_read_value[15:0]; 139 | OP1_PARAM: alu_op1 = param; 140 | OP1_ONE: alu_op1 = 16'd1; 141 | default: alu_op1 = {16{1'bx}}; 142 | endcase 143 | end 144 | 145 | // 146 | // ALU 147 | // 148 | reg[15:0] alu_result; 149 | reg[4:0] alu_op; 150 | wire[15:0] diff = alu_op0 - alu_op1; 151 | wire zero = diff == 0; 152 | wire negative = diff[15]; 153 | 154 | always @* 155 | begin 156 | case (alu_op) 157 | OP_ADD: alu_result = alu_op0 + alu_op1; 158 | OP_SUB: alu_result = diff; 159 | OP_GTR: alu_result = !negative && !zero; 160 | OP_GTE: alu_result = !negative; 161 | OP_EQ: alu_result = zero; 162 | OP_NEQ: alu_result = !zero; 163 | OP_AND: alu_result = alu_op0 & alu_op1; 164 | OP_OR: alu_result = alu_op0 | alu_op1; 165 | OP_XOR: alu_result = alu_op0 ^ alu_op1; 166 | OP_LSHIFT: alu_result = alu_op0 << alu_op1; 167 | OP_RSHIFT: alu_result = alu_op0 >> alu_op1; 168 | default: alu_result = {16{1'bx}}; 169 | endcase 170 | end 171 | 172 | // 173 | // Top of stack next mux 174 | // 175 | localparam TOS_CURRENT = 0; 176 | localparam TOS_TAG = 1; 177 | localparam TOS_RETURN_ADDR = 2; 178 | localparam TOS_FRAME_POINTER = 3; 179 | localparam TOS_PARAM = 4; 180 | localparam TOS_SETTAG = 5; 181 | localparam TOS_ALU_RESULT = 6; 182 | localparam TOS_MEMORY_RESULT = 7; 183 | 184 | reg[2:0] tos_select = TOS_CURRENT; 185 | reg[18:0] top_of_stack_next; 186 | 187 | always @* 188 | begin 189 | case (tos_select) 190 | TOS_CURRENT: top_of_stack_next = top_of_stack; 191 | TOS_TAG: top_of_stack_next = top_of_stack[18:16]; 192 | TOS_RETURN_ADDR: top_of_stack_next = { 3'd0, instruction_pointer + 16'd1 }; 193 | TOS_FRAME_POINTER: top_of_stack_next = { 3'd0, frame_pointer }; 194 | TOS_PARAM: top_of_stack_next = { 3'd0, param }; 195 | TOS_SETTAG: top_of_stack_next = { data_mem_read_value[2:0], top_of_stack[15:0] }; 196 | TOS_ALU_RESULT: top_of_stack_next = { top_of_stack[18:16], alu_result[15:0] }; 197 | TOS_MEMORY_RESULT: top_of_stack_next = data_mem_read_value; 198 | default: top_of_stack_next = {19{1'bx}}; 199 | endcase 200 | end 201 | 202 | // 203 | // Memory address mux 204 | // 205 | localparam MA_STACK_POINTER = 0; 206 | localparam MA_TOP_OF_STACK = 1; 207 | localparam MA_ALU = 2; 208 | localparam MA_FRAME_POINTER = 3; 209 | localparam MA_STACK_POINTER_MINUS_ONE = 4; 210 | 211 | reg[2:0] ma_select = MA_STACK_POINTER; 212 | 213 | always @* 214 | begin 215 | case (ma_select) 216 | MA_STACK_POINTER: data_mem_address = stack_pointer; 217 | MA_TOP_OF_STACK: data_mem_address = top_of_stack[15:0]; 218 | MA_ALU: data_mem_address = alu_result; 219 | MA_FRAME_POINTER: data_mem_address = frame_pointer; 220 | MA_STACK_POINTER_MINUS_ONE: data_mem_address = stack_pointer - 16'd1; 221 | default: data_mem_address = {16{1'bx}}; 222 | endcase 223 | end 224 | 225 | // 226 | // Mem write value mux 227 | // 228 | localparam MW_FRAME_POINTER = 0; 229 | localparam MW_TOP_OF_STACK = 1; 230 | localparam MW_MEM_READ_RESULT = 2; 231 | 232 | reg[1:0] mw_select = MW_FRAME_POINTER; 233 | 234 | always @* 235 | begin 236 | case (mw_select) 237 | MW_FRAME_POINTER: data_mem_write_value = { 3'd0, frame_pointer }; 238 | MW_TOP_OF_STACK: data_mem_write_value = top_of_stack; 239 | MW_MEM_READ_RESULT: data_mem_write_value = data_mem_read_value; 240 | default: data_mem_write_value = {19{1'bx}}; 241 | endcase 242 | end 243 | 244 | // 245 | // Frame pointer mux 246 | // 247 | localparam FP_CURRENT = 0; 248 | localparam FP_ALU = 1; 249 | localparam FP_MEM = 2; 250 | 251 | reg[15:0] frame_pointer_next; 252 | reg[1:0] bp_select = FP_CURRENT; 253 | 254 | always @* 255 | begin 256 | case (bp_select) 257 | FP_CURRENT: frame_pointer_next = frame_pointer; 258 | FP_ALU: frame_pointer_next = alu_result; 259 | FP_MEM: frame_pointer_next = data_mem_read_value[15:0]; 260 | default: frame_pointer_next = {16{1'bx}}; 261 | endcase 262 | end 263 | 264 | // 265 | // Instruction pointer next mux 266 | // 267 | localparam IP_CURRENT = 0; 268 | localparam IP_NEXT = 1; 269 | localparam IP_BRANCH_TARGET = 2; 270 | localparam IP_MEM_READ_RESULT = 3; 271 | localparam IP_STACK_TARGET = 4; 272 | 273 | reg[15:0] instruction_pointer_next; 274 | reg[2:0] ip_select = IP_CURRENT; 275 | assign instr_mem_address = instruction_pointer_next; 276 | 277 | always @* 278 | begin 279 | case (ip_select) 280 | IP_CURRENT: instruction_pointer_next = instruction_pointer; 281 | IP_NEXT: instruction_pointer_next = instruction_pointer + 16'd1; 282 | IP_BRANCH_TARGET: instruction_pointer_next = param; 283 | IP_MEM_READ_RESULT: instruction_pointer_next = data_mem_read_value[15:0]; 284 | IP_STACK_TARGET: instruction_pointer_next = top_of_stack[15:0]; 285 | default: instruction_pointer_next = {16{1'bx}}; 286 | endcase 287 | end 288 | 289 | // 290 | // Main state machine 291 | // 292 | reg[3:0] state_next = STATE_DECODE; 293 | 294 | always @* 295 | begin 296 | state_next = state; 297 | data_mem_write_enable = 0; 298 | ma_select = MA_STACK_POINTER; 299 | mw_select = MW_FRAME_POINTER; 300 | stack_pointer_select = SP_CURRENT; 301 | tos_select = TOS_CURRENT; 302 | bp_select = FP_CURRENT; 303 | alu_op0_select = OP0_TOP_OF_STACK; 304 | alu_op1_select = OP1_MEM_READ; 305 | alu_op = opcode; 306 | ip_select = IP_CURRENT; 307 | 308 | case (state) 309 | STATE_DECODE: 310 | begin 311 | case (opcode) 312 | OP_CALL: 313 | begin 314 | // the next instruction pointer logic will 315 | // use the top of stack as the call-to address, replacing 316 | // it. 317 | // Need to push the old frame pointer on the stack 318 | // and stash the return value in TOS 319 | ip_select = IP_STACK_TARGET; 320 | stack_pointer_select = SP_DECREMENT; 321 | ma_select = MA_ALU; 322 | alu_op0_select = OP0_STACK_POINTER; 323 | alu_op1_select = OP1_ONE; 324 | alu_op = OP_SUB; 325 | data_mem_write_enable = 1; 326 | mw_select = MW_FRAME_POINTER; 327 | bp_select = FP_ALU; 328 | tos_select = TOS_RETURN_ADDR; 329 | state_next = STATE_DECODE; 330 | end 331 | 332 | OP_RETURN: 333 | begin 334 | // A function must push its return value into TOS, 335 | // so we know PC is saved in memory. First fetch that. 336 | ma_select = MA_ALU; 337 | alu_op0_select = OP0_FRAME_POINTER; 338 | alu_op1_select = OP1_ONE; 339 | alu_op = OP_SUB; 340 | state_next = STATE_RETURN2; 341 | end 342 | 343 | OP_POP: // pop 344 | begin 345 | ma_select = MA_STACK_POINTER; 346 | stack_pointer_select = SP_INCREMENT; 347 | state_next = STATE_PUSH_MEM_RESULT; 348 | end 349 | 350 | OP_GETTAG: 351 | begin 352 | tos_select = TOS_TAG; 353 | 354 | // Fetch next instruction 355 | ip_select = IP_NEXT; 356 | state_next = STATE_DECODE; 357 | end 358 | 359 | OP_GETBP: 360 | begin 361 | stack_pointer_select = SP_DECREMENT; 362 | ma_select = MA_ALU; 363 | alu_op0_select = OP0_STACK_POINTER; 364 | alu_op1_select = OP1_ONE; 365 | alu_op = OP_SUB; 366 | data_mem_write_enable = 1; 367 | mw_select = MW_TOP_OF_STACK; 368 | tos_select = TOS_FRAME_POINTER; 369 | ip_select = IP_NEXT; 370 | state_next = STATE_DECODE; 371 | end 372 | 373 | OP_LOAD: 374 | begin 375 | // This just replaces TOS. 376 | ma_select = MA_TOP_OF_STACK; 377 | state_next = STATE_PUSH_MEM_RESULT; 378 | end 379 | 380 | OP_STORE: 381 | begin 382 | // Top of stack is the store address, need to fetch 383 | // the store value from next-on-stack 384 | ma_select = MA_STACK_POINTER; 385 | state_next = STATE_GOT_STORE_VALUE; 386 | end 387 | 388 | OP_SETTAG: 389 | begin 390 | // Need to fetch next-on-stack to get the new tag 391 | ma_select = MA_STACK_POINTER; 392 | state_next = STATE_GOT_NEW_TAG; 393 | end 394 | 395 | // binary operations 396 | OP_ADD, 397 | OP_SUB, 398 | OP_GTR, 399 | OP_GTE, 400 | OP_EQ, 401 | OP_NEQ, 402 | OP_AND, 403 | OP_OR, 404 | OP_XOR, 405 | OP_LSHIFT, 406 | OP_RSHIFT: 407 | begin 408 | // In the first cycle of a store, we need to fetch 409 | // the next value on the stack 410 | ma_select = MA_STACK_POINTER; 411 | state_next = STATE_GOT_NOS; 412 | end 413 | 414 | OP_REST: // Just a load with an extra offset 415 | begin 416 | ma_select = MA_ALU; 417 | alu_op0_select = OP0_TOP_OF_STACK; 418 | alu_op1_select = OP1_ONE; 419 | alu_op = OP_ADD; 420 | state_next = STATE_PUSH_MEM_RESULT; 421 | end 422 | 423 | OP_DUP: // Push TOS, but leave it untouched. 424 | begin 425 | stack_pointer_select = SP_DECREMENT; 426 | ma_select = MA_ALU; 427 | alu_op0_select = OP0_STACK_POINTER; 428 | alu_op1_select = OP1_ONE; 429 | alu_op = OP_SUB; 430 | data_mem_write_enable = 1; 431 | mw_select = MW_TOP_OF_STACK; 432 | ip_select = IP_NEXT; 433 | state_next = STATE_DECODE; 434 | end 435 | 436 | OP_RESERVE: 437 | begin 438 | if (param != 0) 439 | begin 440 | // Store the current TOS to memory and update sp. 441 | // this has the side effect of pushing an 442 | // extra dummy value on the stack. 443 | ma_select = MA_STACK_POINTER_MINUS_ONE; 444 | data_mem_write_enable = 1; 445 | mw_select = MW_TOP_OF_STACK; 446 | stack_pointer_select = SP_ALU; 447 | alu_op = OP_SUB; 448 | alu_op0_select = OP0_STACK_POINTER; 449 | alu_op1_select = OP1_PARAM; 450 | end 451 | 452 | ip_select = IP_NEXT; 453 | state_next = STATE_DECODE; 454 | end 455 | 456 | OP_PUSH: 457 | begin 458 | // Immediate Push. Store the current 459 | // TOS to memory and latch the value into the TOS reg. 460 | stack_pointer_select = SP_DECREMENT; 461 | ma_select = MA_ALU; 462 | alu_op0_select = OP0_STACK_POINTER; 463 | alu_op1_select = OP1_ONE; 464 | alu_op = OP_SUB; 465 | data_mem_write_enable = 1; 466 | mw_select = MW_TOP_OF_STACK; 467 | tos_select = TOS_PARAM; 468 | ip_select = IP_NEXT; 469 | state_next = STATE_DECODE; 470 | end 471 | 472 | OP_GOTO: 473 | begin 474 | ip_select = IP_BRANCH_TARGET; 475 | state_next = STATE_DECODE; 476 | end 477 | 478 | OP_BFALSE: 479 | begin 480 | // Branch if top of stack is 0 481 | if (top_of_stack[15:0] == 0) 482 | ip_select = IP_BRANCH_TARGET; 483 | else 484 | ip_select = IP_NEXT; 485 | 486 | // We popped TOS, so reload it from memory 487 | stack_pointer_select = SP_INCREMENT; 488 | ma_select = MA_STACK_POINTER; 489 | state_next = STATE_BFALSE2; 490 | end 491 | 492 | OP_GETLOCAL: 493 | begin 494 | // First cycle, need to save current TOS into memory. 495 | stack_pointer_select = SP_DECREMENT; 496 | ma_select = MA_ALU; 497 | alu_op0_select = OP0_STACK_POINTER; 498 | alu_op1_select = OP1_ONE; 499 | alu_op = OP_SUB; 500 | data_mem_write_enable = 1; 501 | mw_select = MW_TOP_OF_STACK; 502 | state_next = STATE_GETLOCAL2; 503 | end 504 | 505 | OP_SETLOCAL: 506 | begin 507 | // Write TOS value to appropriate local slot, leave on stack. 508 | ma_select = MA_ALU; 509 | alu_op0_select = OP0_FRAME_POINTER; 510 | alu_op1_select = OP1_PARAM; 511 | alu_op = OP_ADD; 512 | data_mem_write_enable = 1; 513 | mw_select = MW_TOP_OF_STACK; 514 | state_next = STATE_DECODE; 515 | ip_select = IP_NEXT; 516 | end 517 | 518 | OP_CLEANUP: 519 | begin 520 | // cleanup params. The trick is that we leave TOS untouched, 521 | // so the return value will not be affected. 522 | stack_pointer_select = SP_ALU; 523 | alu_op = OP_ADD; 524 | alu_op0_select = OP0_STACK_POINTER; 525 | alu_op1_select = OP1_PARAM; 526 | 527 | // Fetch next instruction 528 | ip_select = IP_NEXT; 529 | state_next = STATE_DECODE; 530 | end 531 | 532 | default: // NOP or any other unknown op 533 | begin 534 | // Fetch next instruction 535 | ip_select = IP_NEXT; 536 | state_next = STATE_DECODE; 537 | end 538 | endcase 539 | end 540 | 541 | STATE_GOT_NEW_TAG: 542 | begin 543 | tos_select = TOS_SETTAG; // Unary, just replace top 544 | stack_pointer_select = SP_INCREMENT; 545 | 546 | // Fetch next instruction 547 | ip_select = IP_NEXT; 548 | state_next = STATE_DECODE; 549 | end 550 | 551 | STATE_GOT_STORE_VALUE: 552 | begin 553 | // Do the store in this cycle and leave the value on the TOS. 554 | data_mem_write_enable = 1; 555 | ma_select = MA_TOP_OF_STACK; 556 | mw_select = MW_MEM_READ_RESULT; 557 | tos_select = TOS_MEMORY_RESULT; 558 | stack_pointer_select = SP_INCREMENT; 559 | ip_select = IP_NEXT; 560 | state_next = STATE_DECODE; 561 | end 562 | 563 | // For any instruction with two stack operands, this is called 564 | // in the second cycle, when the NOS has been fetched. 565 | STATE_GOT_NOS: 566 | begin 567 | // standard binary arithmetic. 568 | alu_op0_select = OP0_TOP_OF_STACK; 569 | alu_op1_select = OP1_MEM_READ; 570 | alu_op = opcode; 571 | tos_select = TOS_ALU_RESULT; 572 | stack_pointer_select = SP_INCREMENT; 573 | 574 | // Fetch next instruction 575 | ip_select = IP_NEXT; 576 | state_next = STATE_DECODE; 577 | end 578 | 579 | STATE_GETLOCAL2: 580 | begin 581 | // Issue memory read for local value 582 | ma_select = MA_ALU; 583 | alu_op0_select = OP0_FRAME_POINTER; 584 | alu_op1_select = OP1_PARAM; 585 | alu_op = OP_ADD; 586 | state_next = STATE_PUSH_MEM_RESULT; 587 | end 588 | 589 | STATE_BFALSE2: 590 | begin 591 | // Latch top of stack and fetch next instruction 592 | // Note that we don't update IP here: it is already loaded 593 | // with the branch target 594 | tos_select = TOS_MEMORY_RESULT; 595 | state_next = STATE_DECODE; 596 | end 597 | 598 | STATE_PUSH_MEM_RESULT: 599 | begin 600 | // Store whatever was returned from memory to the top of stack. 601 | tos_select = TOS_MEMORY_RESULT; 602 | ip_select = IP_NEXT; 603 | state_next = STATE_DECODE; 604 | end 605 | 606 | STATE_RETURN2: 607 | begin 608 | // Got the instruction pointer, now fetch old frame pointer 609 | ip_select = IP_MEM_READ_RESULT; 610 | ma_select = MA_FRAME_POINTER; 611 | stack_pointer_select = SP_ALU; 612 | alu_op = OP_ADD; 613 | alu_op0_select = OP0_FRAME_POINTER; 614 | alu_op1_select = OP1_ONE; 615 | state_next = STATE_RETURN3; 616 | end 617 | 618 | STATE_RETURN3: 619 | begin 620 | // Note: proper next PC has already been fetched, so don't 621 | // increment here. 622 | bp_select = FP_MEM; 623 | state_next = STATE_DECODE; 624 | end 625 | endcase 626 | end 627 | 628 | always @(posedge reset, posedge clk) 629 | begin 630 | if (reset) 631 | begin 632 | state <= STATE_DECODE; 633 | top_of_stack <= 0; 634 | stack_pointer <= DATA_MEM_SIZE - 16'd8; 635 | frame_pointer <= DATA_MEM_SIZE - 16'd4; 636 | instruction_pointer <= 16'hffff; 637 | end 638 | else 639 | begin 640 | instruction_pointer <= instruction_pointer_next; 641 | state <= state_next; 642 | top_of_stack <= top_of_stack_next; 643 | stack_pointer <= stack_pointer_next; 644 | frame_pointer <= frame_pointer_next; 645 | end 646 | end 647 | endmodule 648 | 649 | -------------------------------------------------------------------------------- /ram.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | module ram 20 | #(parameter MEM_SIZE = 4096, 21 | parameter WORD_SIZE = 20, 22 | parameter ADDR_SIZE = 16) 23 | 24 | (input clk, 25 | input[ADDR_SIZE - 1:0] addr_i, 26 | input[WORD_SIZE - 1:0] value_i, 27 | input write_i, 28 | output reg[WORD_SIZE - 1:0] value_o); 29 | 30 | reg[WORD_SIZE - 1:0] data[0:MEM_SIZE]; 31 | integer i; 32 | 33 | initial 34 | begin 35 | // synthesis translate_off 36 | for (i = 0; i < MEM_SIZE; i = i + 1) 37 | data[i] = 0; 38 | // synthesis translate_on 39 | end 40 | 41 | always @(posedge clk) 42 | begin 43 | if (write_i) 44 | data[addr_i] <= value_i; 45 | 46 | value_o <= data[addr_i]; 47 | end 48 | endmodule 49 | -------------------------------------------------------------------------------- /rom.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | module rom 20 | #(parameter MEM_SIZE = 4096, 21 | parameter WORD_SIZE = 20, 22 | parameter ADDR_SIZE = 16, 23 | parameter INIT_FILE="") 24 | 25 | (input clk, 26 | input[ADDR_SIZE - 1:0] addr_i, 27 | output reg[WORD_SIZE - 1:0] value_o); 28 | 29 | reg[WORD_SIZE - 1:0] data[0:MEM_SIZE]; 30 | integer i; 31 | 32 | initial 33 | begin 34 | // synthesis translate_off 35 | for (i = 0; i < MEM_SIZE; i = i + 1) 36 | data[i] = 0; 37 | // synthesis translate_on 38 | 39 | $readmemh(INIT_FILE, data); 40 | end 41 | 42 | always @(posedge clk) 43 | value_o <= data[addr_i]; 44 | endmodule 45 | -------------------------------------------------------------------------------- /runtime.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Library of standard macros and runtime functions 18 | 19 | (defmacro foreach (var list expr) 20 | `(let ((,var nil)(nodeptr ,list)) 21 | (while nodeptr 22 | (assign ,var (first nodeptr)) 23 | ,expr 24 | (assign nodeptr (rest nodeptr))))) 25 | 26 | (defmacro for (var start end step expr) 27 | `(if (< ,step 0) 28 | ; Decrementing 29 | (let ((,var ,start) (__endval ,end)) 30 | (while (>= ,var __endval) 31 | ,expr 32 | (assign ,var (+ ,var ,step)))) 33 | 34 | ; Incrementing 35 | (let ((,var ,start)(__endval ,end)) 36 | (while (<= ,var __endval) 37 | ,expr 38 | (assign ,var (+ ,var ,step)))))) 39 | 40 | (defmacro when (val pred) 41 | `(if ,val 42 | ,pred)) 43 | 44 | (defmacro unless (val pred) 45 | `(if (not ,val) 46 | ,pred)) 47 | 48 | (defmacro write-register (index value) 49 | `(store (- ,index 4096) ,value)) 50 | 51 | (defmacro read-register (index) 52 | `(load (- ,index 4096))) 53 | 54 | ; For debugging, uncomment the printchar lines to log GC actions 55 | (defmacro gclog (prefix address) 56 | `(begin 57 | ; ($printchar ,prefix) 58 | ; ($printhex ,address) 59 | ; ($printchar #\newline) 60 | )) 61 | 62 | (defmacro atom? (ptr) 63 | `(= (bitwise-and (gettag ,ptr) 3) 0)) 64 | 65 | (defmacro list? (ptr) 66 | `(= (bitwise-and (gettag ,ptr) 3) 1)) 67 | 68 | (defmacro function? (ptr) 69 | `(= (bitwise-and (gettag ,ptr) 3) 2)) 70 | 71 | (defmacro closure? (ptr) 72 | `(= (bitwise-and (gettag ,ptr) 3) 3)) 73 | 74 | (defmacro nil? (ptr) 75 | `(not ,ptr)) 76 | 77 | (defmacro setfirst (ptr val) 78 | `(store ,ptr ,val)) 79 | 80 | (defmacro setnext (ptr next) 81 | `(store (+ ,ptr 1) ,next)) 82 | 83 | ; In testbench.v, when register 4095 is written, the simulator will exit 84 | (function halt () 85 | (write-register 4095 0)) 86 | 87 | ; Note that $heapstart is a variable created automatically 88 | ; by the compiler. Wilderness is memory that has never been allocated and 89 | ; that we can simply slice off from. 90 | (assign $wilderness-start $heapstart) 91 | 92 | ; This is called from top level main, so BP will be top of stack 93 | (assign $stacktop (getbp)) 94 | (assign $max-heap (- $stacktop 1024)) 95 | (assign $freelist nil) 96 | 97 | ; Mark a pointer, following links if it is a pair 98 | (function $mark-recursive (ptr) 99 | ; Check if this is a cons/closure and is not null 100 | (when (and ptr (or (list? ptr) (closure? ptr))) 101 | (begin 102 | (let ((firstword (load ptr)) (tag (gettag firstword))) 103 | (when (not (rshift tag 2)) 104 | (begin 105 | ; An unmarked cons cell, mark it and continue 106 | (gclog #\M ptr) 107 | (store ptr (settag firstword (bitwise-or tag 4))) 108 | 109 | ; Check if we need to mark the first pointer 110 | ($mark-recursive (first ptr))))) 111 | ($mark-recursive (rest ptr))))) 112 | 113 | ; Mark a range of contiguous addresses. 114 | (function $mark-range (start end) 115 | (for addr start end 1 116 | ($mark-recursive (load addr)))) 117 | 118 | ; Garbage collect, using mark-sweep algorithm 119 | (function $gc () 120 | (gclog #\G $wilderness-start) 121 | 122 | ;;; Mark phase 123 | 124 | ; Clear GC flags 125 | (for ptr $heapstart (- $wilderness-start 1) 2 126 | (let ((val (load ptr)) (tag (gettag val))) 127 | (store ptr (settag val (bitwise-and tag 3))))) 128 | ($mark-range 0 $heapstart) ; Mark global variables 129 | ($mark-range (getbp) $stacktop) ; Mark stack 130 | 131 | ;;; Sweep phase 132 | (assign $freelist nil) ; First clear the freelist so we don't double-add 133 | (for ptr $heapstart (- $wilderness-start 1) 2 134 | (unless (bitwise-and (gettag (load ptr)) 4) 135 | (begin 136 | ; This is not used, stick it back in the free list. 137 | (store (+ 1 ptr) $freelist) 138 | (assign $freelist ptr) 139 | (gclog #\F ptr))))) 140 | 141 | ; Called when we run out of memory 142 | (function $oom () 143 | ; Can't use a string here, since that requires allocations 144 | ; and would cause infinite recursion. 145 | ($printchar #\O) 146 | ($printchar #\O) 147 | ($printchar #\M) 148 | ($printchar #\newline) 149 | (halt)) 150 | 151 | ; Allocate a new cell and return a pointer to it 152 | (function cons (_first _rest) 153 | (let ((ptr nil)) 154 | (if $freelist 155 | ; There are nodes on freelist, grab one. 156 | (begin 157 | (assign ptr $freelist) 158 | (assign $freelist (rest ptr))) 159 | ; Nothing on freelist, try to expand frontier 160 | (begin 161 | (if (< $wilderness-start $max-heap) 162 | ; Space is available in frontier, snag from there. 163 | (begin 164 | (assign ptr $wilderness-start) 165 | (assign $wilderness-start (+ $wilderness-start 2))) 166 | ; No more space available, need to garbage collect 167 | (begin 168 | ($gc) 169 | (if $freelist 170 | ; Then: got a block, assign it 171 | (begin 172 | (assign ptr $freelist) 173 | (assign $freelist (rest ptr))) 174 | 175 | ; Else: GC gave us nothing, give up. 176 | ($oom)))))) 177 | (gclog #\A ptr) ; debug: print cell that has been allocated 178 | (store ptr _first) 179 | (store (+ ptr 1) _rest) 180 | (settag ptr 1))) ; Mark this as a cons cell and return 181 | 182 | (function abs (x) 183 | (if (< x 0) 184 | (- 0 x) 185 | x)) 186 | 187 | (function $umul (multiplicand multiplier) 188 | (let ((product 0)) 189 | (while multiplier 190 | (when (bitwise-and multiplier 1) 191 | (assign product (+ product multiplicand))) 192 | (assign multiplier (rshift multiplier 1)) 193 | (assign multiplicand (lshift multiplicand 1))) 194 | product)) 195 | 196 | (function * (multiplicand multiplier) 197 | (let ((uprod ($umul (abs multiplicand) (abs multiplier)))) 198 | (if (= (< multiplicand 0) (< multiplier 0)) 199 | uprod ; same sign 200 | (- 0 uprod)))) ; different signs 201 | 202 | ; Unsigned divide. If getrem is 1, this will return the remainder. Otherwise 203 | ; it will return the quotient 204 | (function $udiv (divisor dividend getrem) 205 | (if (< divisor dividend) 206 | ; If the divisor is less than the divident, division result will 207 | ; be zero 208 | (if getrem 209 | divisor 210 | 0) 211 | ; Need to do division 212 | (let ((quotient 0) (dnext dividend) (numbits 0)) 213 | ; Align remainder and divisor 214 | (while (<= dnext divisor) 215 | (assign dividend dnext) 216 | (assign numbits (+ numbits 1)) 217 | (assign dnext (lshift dnext 1))) 218 | ; Divide 219 | (while numbits 220 | (assign quotient (lshift quotient 1)) 221 | (when (>= divisor dividend) 222 | (begin 223 | (assign divisor (- divisor dividend)) 224 | (assign quotient (bitwise-or quotient 1)))) 225 | (assign dividend (rshift dividend 1)) 226 | (assign numbits (- numbits 1))) 227 | (if getrem 228 | divisor 229 | quotient)))) 230 | 231 | (function / (divisor dividend) 232 | (let ((uquotient ($udiv (abs divisor) (abs dividend) 0))) 233 | (if (= (< divisor 0) (< dividend 0)) 234 | uquotient ; same sign 235 | (- 0 uquotient)))) ; different signs 236 | 237 | (function mod (divisor dividend) 238 | (let ((uremainder ($udiv (abs divisor) (abs dividend) 1))) 239 | (if (< dividend 0) 240 | (- 0 uremainder) 241 | uremainder))) 242 | 243 | (function sqrt (num) 244 | (let ((guess num) (lastguess (+ num 3))) 245 | (while (> (- lastguess guess) 2) 246 | (assign lastguess guess) 247 | (assign guess (/ (+ guess (/ num guess)) 2))) 248 | guess)) 249 | 250 | (function $printchar (x) 251 | (write-register 0 x)) 252 | 253 | (function $printstr (x) 254 | (foreach ch x 255 | ($printchar ch))) 256 | 257 | ; Print a number in decimal format 258 | (function $printdec (num) 259 | (when (< num 0) 260 | (begin 261 | ; Negative number 262 | (assign num (- 0 num)) 263 | ($printchar #\-))) 264 | (if num 265 | ; Not zero 266 | (let ((str nil)) 267 | (while num 268 | (assign str (cons (mod num 10) str)) 269 | (assign num (/ num 10))) 270 | (foreach ch str 271 | ($printchar (+ #\0 ch)))) 272 | ; Is zero 273 | ($printchar #\0))) 274 | 275 | (function $printhex (num) 276 | (for idx 0 15 4 277 | (let ((digit (bitwise-and (rshift num (- 12 idx)) 15))) 278 | (if (< digit 10) 279 | ($printchar (+ digit #\0)) 280 | ($printchar (+ digit (- #\A 10))))))) ; - 10 + 'A' 281 | 282 | (function print (x) 283 | (when (list? x) 284 | (begin 285 | ($printchar 40) ; Open paren 286 | (let ((needspace false)) 287 | (foreach element x 288 | (begin 289 | (if needspace 290 | ($printchar #\space) 291 | (assign needspace true)) 292 | (print element)))) 293 | ($printchar 41))) ; Close paren 294 | (when (atom? x) 295 | ; This is a number 296 | ($printdec x)) 297 | (when (function? x) 298 | (begin 299 | ($printstr "function") 300 | ($printhex x))) 301 | (when (closure? x) 302 | (begin 303 | ($printstr "closure ") 304 | (print (rest x))))) 305 | 306 | ; Walk down the list and return the element at the given index 307 | (function nth (list index) 308 | (if list 309 | (if index 310 | (nth (rest list) (- index 1)) ; Keep traversing 311 | (first list)) ; Found item at index 312 | nil)) ; Index is beyond length of list 313 | 314 | (function $$length-helper (list length) 315 | (if list 316 | ($$length-helper (rest list) (+ length 1)) 317 | length)) 318 | 319 | ; Return number of elements in the list 320 | (function length (list) 321 | ($$length-helper list 0)) 322 | 323 | ; Create a new list that contains all elements if the original with 324 | ; a new element added on. 325 | (function append (prefix element) 326 | (if prefix 327 | ; Append to existing list 328 | (let ((suffix (if (list? element) element (cons element nil))) 329 | (newhead (cons (first prefix) nil)) (newtail newhead)) 330 | (foreach entry (rest prefix) 331 | (begin 332 | ; Append entry to end of new list 333 | (setnext newtail (cons entry nil)) 334 | (assign newtail (rest newtail)))) 335 | (setnext newtail suffix) 336 | newhead) 337 | ; prefix is nil, create list with one element 338 | (cons element nil))) 339 | 340 | (function $$reverse_recursive (forward backward) 341 | (if forward 342 | ($$reverse_recursive (rest forward) (cons (first forward) backward)) 343 | backward)) 344 | 345 | ; Creates a new list that has the same elements in the original but in 346 | ; reverse order. 347 | (function reverse (list) 348 | ($$reverse_recursive list nil)) 349 | 350 | (function $compare-lists (list1 list2) 351 | (if (equal (first list1) (first list2)) 352 | (if (rest list1) 353 | (if (rest list2) 354 | ($compare-lists (rest list1) (rest list2)) 355 | false) ; l2 is shorter than l1 356 | (if (rest list2) 357 | false ; l1 is shorter than l2 358 | true)) ; End of both lists, equal 359 | false)) 360 | 361 | ; Check if two value are isomorphic (have the same form). For example, 362 | ; if two lists contain the same elements. 363 | (function equal (a b) 364 | (if (list? a) 365 | (if (list? b) 366 | ($compare-lists a b) 367 | false) 368 | (= a b))) ; Non list type, compare directly 369 | 370 | ; Call func on each item in the list. Create a new list that 371 | ; contains only items that func returned a non-zero value for. 372 | (function filter (list func) 373 | (if list 374 | (if (func (first list)) 375 | (cons (first list) (filter (rest list) func)) ; add to list 376 | (filter (rest list) func)) ; skip this item 377 | nil)) ; end of list 378 | 379 | ; Map calls the given function with each list element as a parameter, then 380 | ; creates a new list with the substituted values (sometimes called mapcar in 381 | ; other lisp implementations). 382 | (function map (values func) 383 | (if values 384 | (cons (func (first values)) (map (rest values) func)) 385 | nil)) 386 | 387 | (function $reduce-helper (accum values func) 388 | (if values 389 | ($reduce-helper (func accum (first values)) (rest values) func) 390 | accum)) 391 | 392 | ; Given a list reduce will call a function that takes two parameters 393 | ; repeatedly and return a single result. e.g. 394 | ; (reduce '(1 2 3 4 5) add) 395 | ; will return the result of (add (add (add (add 1 2) 3) 4) 5) 396 | (function reduce (values func) 397 | (if values 398 | (if (rest values) 399 | ($reduce-helper (first values) (rest values) func) 400 | (first values)) 401 | nil)) 402 | 403 | (function $match-substring (haystack needle) 404 | (if needle 405 | (if (= (first haystack) (first needle)) 406 | (if haystack 407 | ($match-substring (rest haystack) (rest needle)) 408 | false) ; Character mismatch 409 | false) ; End of haystack, no match 410 | true)) ; Match 411 | 412 | (function $find-string-helper (offset haystack needle) 413 | (if haystack 414 | (if (not ($match-substring haystack needle)) 415 | ($find-string-helper (+ offset 1) (rest haystack) needle) 416 | offset) 417 | -1)) 418 | 419 | (function find-string (haystack needle) 420 | ($find-string-helper 0 haystack needle)) 421 | 422 | (function sub-list (source start len) 423 | (let ((newhead nil) (newtail nil) (from source)) 424 | ; Skip elements in source list 425 | (while (and from start) 426 | (assign from (rest from)) 427 | (assign start (- start 1))) 428 | ; Copy len remaining entries if present 429 | (if from 430 | (begin 431 | (while (and from len) 432 | (if (not newhead) 433 | (begin 434 | (assign newhead (cons (first from) nil)) 435 | (assign newtail newhead)) 436 | (begin 437 | (setnext newtail (cons (first from) nil)) 438 | (assign newtail (rest newtail)))) 439 | 440 | (assign from (rest from)) 441 | (assign len (- len 1))) 442 | newhead) 443 | nil))) 444 | -------------------------------------------------------------------------------- /testbench.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | //`define TRACE 1 20 | 21 | module testbench; 22 | 23 | reg clk; 24 | reg reset; 25 | integer i; 26 | integer j; 27 | wire[11:0] register_index; 28 | wire register_read; 29 | wire register_write; 30 | wire[15:0] register_write_value; 31 | reg[15:0] register_read_value = 0; 32 | reg halt = 0; 33 | 34 | ulisp l( 35 | .clk(clk), 36 | .reset(reset), 37 | .register_index(register_index), 38 | .register_read(register_read), 39 | .register_write(register_write), 40 | .register_write_value(register_write_value), 41 | .register_read_value(register_read_value)); 42 | 43 | initial 44 | begin 45 | clk = 0; 46 | #5 reset = 1; 47 | #5 reset = 0; 48 | 49 | //$dumpfile("trace.vcd"); 50 | //$dumpvars(100, l); 51 | 52 | for (i = 0; i < 2000000 && !halt; i = i + 1) 53 | begin 54 | #5 clk = ~clk; 55 | 56 | `ifdef TRACE 57 | if (clk) dumpstate; 58 | `endif 59 | end 60 | end 61 | 62 | always @(posedge clk) 63 | begin 64 | if (register_write) 65 | begin 66 | if (register_index == 0) 67 | $write("%c", register_write_value); 68 | else if (register_index == 4095) 69 | begin 70 | $display("HALTED"); 71 | halt = 1; 72 | end 73 | else 74 | $display("set register %d <= %d", register_index, register_write_value); 75 | end 76 | end 77 | 78 | task dumpstate; 79 | begin 80 | if (l.c.opcode != 0) 81 | begin 82 | $write("%05d ", l.c.instruction_pointer); 83 | 84 | case (l.c.opcode) 85 | l.c.OP_NOP: $write("nop "); 86 | l.c.OP_CALL: $write("call "); 87 | l.c.OP_RETURN: $write("return "); 88 | l.c.OP_POP: $write("pop "); 89 | l.c.OP_LOAD: $write("load "); 90 | l.c.OP_STORE: $write("store "); 91 | l.c.OP_ADD: $write("add "); 92 | l.c.OP_SUB: $write("sub "); 93 | l.c.OP_REST: $write("rest "); 94 | l.c.OP_GTR: $write("gtr "); 95 | l.c.OP_GTE: $write("gte "); 96 | l.c.OP_EQ: $write("eq "); 97 | l.c.OP_NEQ: $write("neq "); 98 | l.c.OP_DUP: $write("dup "); 99 | l.c.OP_GETTAG: $write("gettag "); 100 | l.c.OP_SETTAG: $write("settag "); 101 | l.c.OP_RESERVE: $write("reserve "); 102 | l.c.OP_PUSH: $write("push "); 103 | l.c.OP_GOTO: $write("goto "); 104 | l.c.OP_BFALSE: $write("bfalse "); 105 | l.c.OP_GETLOCAL: $write("getlocal"); 106 | l.c.OP_SETLOCAL: $write("setlocal"); 107 | l.c.OP_CLEANUP: $write("cleanup "); 108 | l.c.OP_AND: $write("and "); 109 | l.c.OP_OR: $write("or "); 110 | l.c.OP_XOR: $write("xor "); 111 | l.c.OP_LSHIFT: $write("lshift "); 112 | l.c.OP_RSHIFT: $write("rshift "); 113 | l.c.OP_GETBP: $write("getbp "); 114 | endcase 115 | 116 | if (l.c.opcode[4:3] == 2'b11) 117 | $write(" %05d", l.c.param); 118 | else 119 | $write(" "); 120 | 121 | $write(" "); 122 | 123 | case (l.c.state) 124 | l.c.STATE_DECODE: $write("DECODE "); 125 | l.c.STATE_GOT_NOS: $write("GOT_NOS "); 126 | l.c.STATE_PUSH_MEM_RESULT: $write("PUSH_MEM_RESULT"); 127 | l.c.STATE_GETLOCAL2: $write("GETLOCAL2 "); 128 | l.c.STATE_RETURN2: $write("RETURN2 "); 129 | l.c.STATE_RETURN3: $write("RETURN3 "); 130 | l.c.STATE_GOT_STORE_VALUE: $write("GOT_STORE_VALUE"); 131 | l.c.STATE_GOT_NEW_TAG: $write("GOT_NEW_TAG "); 132 | l.c.STATE_BFALSE2: $write("BFALSE2 "); 133 | endcase 134 | 135 | $write(" stack(%05d) ", l.c.stack_pointer); 136 | $write(" %05d", l.c.top_of_stack); 137 | for (j = 0; j < 5; j = j + 1) 138 | $write(" %05d", l.data_mem.data[l.c.stack_pointer + j]); 139 | 140 | $write("\n"); 141 | if (l.c.instruction_pointer_next != l.c.instruction_pointer) 142 | $write("\n"); 143 | 144 | // if (l.mem_write_enable) 145 | // $display(" mem %d <= %d", l.mem_addr, l.mem_write_value); 146 | end 147 | end 148 | endtask 149 | 150 | 151 | endmodule 152 | -------------------------------------------------------------------------------- /tests/anagram.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2013 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (function removenth (list index) 18 | (if (and index (rest list)) 19 | (cons (first list) (removenth (rest list) (- index 1))) ; then keep searching 20 | (rest list))) ; else at index or end of list, return the next after 21 | 22 | (function anagram (prefix suffix) 23 | (if suffix 24 | ; then select next letter 25 | (for x 0 (- (length suffix) 1) 1 26 | (anagram (append prefix (nth suffix x)) (removenth suffix x))) 27 | ; else print the final value 28 | ($printstr prefix))) 29 | 30 | ($printchar #\X) 31 | (anagram nil "lisp") 32 | ($printchar #\Y) 33 | 34 | ; CHECK: XlisplipslsiplspilpislpsiilspilpsislpispliplsipslslipslpisilpsiplsplispilplisplsipilspislpslipsilY 35 | 36 | -------------------------------------------------------------------------------- /tests/anonfunc.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (print ((function (x y) (+ x y)) 2 3)) 18 | ; CHECK: 5 19 | 20 | (function mkcomp () (function (z) (+ z 13))) 21 | (print ((mkcomp) 19)) 22 | ; CHECK: 32 23 | -------------------------------------------------------------------------------- /tests/breakloop.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Conditional break 18 | (print 19 | (while true 20 | (print j) 21 | (if (= j 7) 22 | (break 37)) 23 | 24 | (assign j (+ j 1)))) 25 | 26 | ; CHECK: 0 27 | ; CHECK: 1 28 | ; CHECK: 2 29 | ; CHECK: 3 30 | ; CHECK: 4 31 | ; CHECK: 5 32 | ; CHECK: 6 33 | ; CHECK: 7 34 | ; CHECK: 37 35 | 36 | ; Break inner loop of nested loop. Ensure break stack works properly. 37 | (for i 3 4 1 38 | (print 39 | (for j 1 5 1 40 | (break i)))) 41 | 42 | ; CHECK: 3 43 | ; CHECK: 4 44 | 45 | ; Break outer loop of nested loop. 46 | (print (while true 47 | (for j 17 19 1 48 | (print j)) 49 | 50 | (break 99))) 51 | 52 | ; CHECK: 17 53 | ; CHECK: 18 54 | ; CHECK: 19 55 | ; CHECK: 99 56 | -------------------------------------------------------------------------------- /tests/closure.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (function make_between (low high) 18 | (function (value) (and (>= value low) (<= value high)))) 19 | 20 | (assign check (make_between 3 5)) 21 | 22 | (print check) ; CHECK: closure (3 5) 23 | 24 | ; Run a GC to ensure the closure is properly marked 25 | ($gc) 26 | 27 | ; If the GC did free the closure, this will clobber it 28 | (cons 0 0) 29 | 30 | ; Now test that the closure works correctly 31 | (for x 0 10 1 32 | (if (check x) ($printchar #\T) ($printchar #\F))) 33 | 34 | ; CHECK: FFFTTTFFFF 35 | 36 | 37 | ; Verify that, if a free variable is copied from a function outside the 38 | ; immediate parent, it is copied across all function (create shadow 39 | ; closures in intermediate functions). 40 | (function foo (a) 41 | (function () 42 | (function () 43 | (function () 44 | (print a))))) 45 | 46 | ((((foo 19)))) ; CHECK: 19 47 | 48 | ; Update variable inside a closure 49 | ; Because we capture by value and not reference, the updated value does 50 | ; not affect the closure. 51 | (function make_func1 (a) 52 | (function () 53 | (assign a (+ a 1)) 54 | (print a))) 55 | 56 | (assign func1 (make_func1 17)) 57 | (func1) ; CHECK: 18 58 | (func1) ; CHECK: 18 59 | (func1) ; CHECK: 18 60 | 61 | ; Update outer variable after creating closure. Ensure closure has old value. 62 | (function make_func2 () 63 | (let ((a 37) (b (function () (print a)))) 64 | (assign a 2) 65 | b)) 66 | 67 | ((make_func2)) ; CHECK: 37 68 | 69 | ; Update variable inside closure. Check that outer variable isn't affected 70 | (function test_update_inside () 71 | (let ((a 47)) 72 | ((function () (assign a 51))) 73 | (print a))) 74 | 75 | (test_update_inside) ; CHECK 47 76 | 77 | ; Multiple closures share a variable. 78 | ; Calling the function only updates local copy 79 | (function make_funcs1 () 80 | (let ((funclist nil) (x 0)) 81 | (while (< x 10) 82 | (assign funclist (cons (function () (print x)) funclist)) 83 | (assign x (+ x 1))) 84 | funclist)) 85 | 86 | (foreach func (make_funcs1) 87 | (func)) 88 | 89 | ; CHECK: 9876543210 90 | 91 | ; We can share a variable by creating a reference to a cons cell. 92 | ; When each closure runs, it updates the cell. 93 | (function make_funcs2 () 94 | (let ((funclist nil) (sharedref (cons 27 0))) 95 | (for x 0 5 1 96 | (assign funclist (cons (function () 97 | (setfirst sharedref (+ (first sharedref) 1)) 98 | (print (first sharedref))) funclist))) 99 | funclist)) 100 | 101 | (foreach func (make_funcs2) 102 | (func)) 103 | 104 | ; CHECK: 2829303132 105 | -------------------------------------------------------------------------------- /tests/compile-fail.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; This will fail to compile because it is missing a paren 18 | 19 | ((foo 12) 20 | ; CHECK: ignore me -------------------------------------------------------------------------------- /tests/conditionals.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Use variables so the optimizer doesn't hard code these values 18 | (assign yes 1) 19 | (assign no 0) 20 | 21 | (if yes (print 1) (print 0)) ; CHECK: 1 22 | (if no (print 1) (print 0)) ; CHECK: 0 23 | 24 | ; Test bare logical forms with 2 and 3 arguments. These get compiled differently 25 | ; than if because of short circuit evaluation. 26 | (print (and no no)) ; CHECK: 0 27 | (print (and no yes)) ; CHECK: 0 28 | (print (and yes no)) ; CHECK: 0 29 | (print (and yes yes)) ; CHECK: 1 30 | (print (and no no no)) ; CHECK: 0 31 | (print (and no no yes)) ; CHECK: 0 32 | (print (and no yes no)) ; CHECK: 0 33 | (print (and no yes yes)) ; CHECK: 0 34 | (print (and yes no no)) ; CHECK: 0 35 | (print (and yes no yes)) ; CHECK: 0 36 | (print (and yes yes no)) ; CHECK: 0 37 | (print (and yes yes yes)) ; CHECK: 1 38 | 39 | ; If forms of the same 40 | (if (and no no) (print 1) (print 0)) ; CHECK: 0 41 | (if (and no yes) (print 1) (print 0)) ; CHECK: 0 42 | (if (and yes no) (print 1) (print 0)) ; CHECK: 0 43 | (if (and yes yes) (print 1) (print 0)) ; CHECK: 1 44 | (if (and no no no) (print 1) (print 0)) ; CHECK: 0 45 | (if (and no no yes) (print 1) (print 0)) ; CHECK: 0 46 | (if (and no yes no) (print 1) (print 0)) ; CHECK: 0 47 | (if (and no yes yes) (print 1) (print 0)) ; CHECK: 0 48 | (if (and yes no no) (print 1) (print 0)) ; CHECK: 0 49 | (if (and yes no yes) (print 1) (print 0)) ; CHECK: 0 50 | (if (and yes yes no) (print 1) (print 0)) ; CHECK: 0 51 | (if (and yes yes yes) (print 1) (print 0)) ; CHECK: 1 52 | 53 | ; Perform same tests as above with or 54 | (print (or no no)) ; CHECK: 0 55 | (print (or no yes)) ; CHECK: 1 56 | (print (or yes no)) ; CHECK: 1 57 | (print (or yes yes)) ; CHECK: 1 58 | 59 | (print (or no no no)) ; CHECK: 0 60 | (print (or no no yes)) ; CHECK: 1 61 | (print (or no yes no)) ; CHECK: 1 62 | (print (or no yes yes)) ; CHECK: 1 63 | (print (or yes no no)) ; CHECK: 1 64 | (print (or yes no yes)) ; CHECK: 1 65 | (print (or yes yes no)) ; CHECK: 1 66 | (print (or yes yes yes)) ; CHECK: 1 67 | 68 | (if (or no no) (print 1) (print 0)) ; CHECK: 0 69 | (if (or no yes) (print 1) (print 0)) ; CHECK: 1 70 | (if (or yes no) (print 1) (print 0)) ; CHECK: 1 71 | (if (or yes yes) (print 1) (print 0)) ; CHECK: 1 72 | 73 | (if (or no no no) (print 1) (print 0)) ; CHECK: 0 74 | (if (or no no yes) (print 1) (print 0)) ; CHECK: 1 75 | (if (or no yes no) (print 1) (print 0)) ; CHECK: 1 76 | (if (or no yes yes) (print 1) (print 0)) ; CHECK: 1 77 | (if (or yes no no) (print 1) (print 0)) ; CHECK: 1 78 | (if (or yes no yes) (print 1) (print 0)) ; CHECK: 1 79 | (if (or yes yes no) (print 1) (print 0)) ; CHECK: 1 80 | (if (or yes yes yes) (print 1) (print 0)) ; CHECK: 1 81 | 82 | ; Mix and/or 83 | (if (and (or no no) no) (print 1) (print 0)) ; CHECK: 0 84 | (if (and (or no no) yes) (print 1) (print 0)) ; CHECK: 0 85 | (if (and (or no yes) no) (print 1) (print 0)) ; CHECK: 0 86 | (if (and (or no yes) yes) (print 1) (print 0)) ; CHECK: 1 87 | (if (and (or yes no) no) (print 1) (print 0)) ; CHECK: 0 88 | (if (and (or yes no) yes) (print 1) (print 0)) ; CHECK: 1 89 | (if (and (or yes yes) no) (print 1) (print 0)) ; CHECK: 0 90 | (if (and (or yes yes) yes) (print 1) (print 0)) ; CHECK: 1 91 | 92 | (if (or (and no no) no) (print 1) (print 0)) ; CHECK: 0 93 | (if (or (and no no) yes) (print 1) (print 0)) ; CHECK: 1 94 | (if (or (and no yes) no) (print 1) (print 0)) ; CHECK: 0 95 | (if (or (and no yes) yes) (print 1) (print 0)) ; CHECK: 1 96 | (if (or (and yes no) no) (print 1) (print 0)) ; CHECK: 0 97 | (if (or (and yes no) yes) (print 1) (print 0)) ; CHECK: 1 98 | (if (or (and yes yes) no) (print 1) (print 0)) ; CHECK: 1 99 | (if (or (and yes yes) yes) (print 1) (print 0)) ; CHECK: 1 100 | 101 | ; Make sure the value of the if expression itself is correct 102 | (print (if yes 37 21)) ; CHECK: 37 103 | (print (if no 51 72)) ; CHECK: 72 104 | 105 | ; Validate short circuit evaluation. 106 | (and yes (print 97)) ; CHECK: 97 107 | (and no (print 1)) 108 | (or yes (print 1)) 109 | (or no (print 34)) ; CHECK: 34 110 | 111 | ; unless and when macros (which just wrap ifs) 112 | (unless no ($printchar #\A)) 113 | (unless yes ($printchar #\B)) 114 | (when no ($printchar #\C)) 115 | (when yes ($printchar #\D)) 116 | ; CHECK: AD 117 | -------------------------------------------------------------------------------- /tests/dict.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; A dictionary consists of ((name . value) (name . value) (name . value)) 18 | 19 | ; Find an item in a dictionary. Return nil if it is not present. 20 | (function dict-lookup (dict name) 21 | (if dict 22 | (if (= name (first (first dict))) ; then check if key matches 23 | (second (first dict)) ; then match, return value 24 | (dict-lookup (rest dict) name)) ; else lookup in remaining elements 25 | nil)) ; else not found 26 | 27 | ; Create a new dictionary list with the name value pair added. If the key name 28 | ; is already in the list, replace it. 29 | (function dict-set (dict name value) 30 | (if dict 31 | (if (= name (first (first dict))) ; then check if key matches 32 | (cons (cons name value) (rest dict)) ; then key exists, replace 33 | (cons (first dict) (dict-set (rest dict) name value))) ; else search rest of list 34 | (cons (cons name value) nil))) ; else no match, add new entry 35 | 36 | ; Add some entries 37 | (assign dict nil) 38 | (assign dict (dict-set dict 1 7)) 39 | (assign dict (dict-set dict 2 9)) 40 | (assign dict (dict-set dict 3 5)) 41 | (assign dict (dict-set dict 2 8)) ; Replace second entry 42 | 43 | (foreach i dict 44 | (begin 45 | (print (first i)) 46 | (print (second i)))) 47 | 48 | ; CHECK: 17 49 | ; CHECK: 28 50 | ; CHECK: 35 51 | 52 | ; Do some lookups 53 | (print (dict-lookup dict 1)) ; CHECK: 7 54 | (print (dict-lookup dict 2)) ; CHECK: 8 55 | (print (dict-lookup dict 3)) ; CHECK: 5 56 | (print (dict-lookup dict 4)) ; CHECK: 0 57 | 58 | 59 | -------------------------------------------------------------------------------- /tests/fib.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; 18 | ; Recursive function call with conditional 19 | ; 20 | 21 | (function fib (n) 22 | (if (< n 2) 23 | n 24 | (+ (fib (- n 1)) (fib (- n 2))))) 25 | 26 | (for i 0 10 1 27 | (print (fib i))) 28 | 29 | ; CHECK: 0 30 | ; CHECK: 1 31 | ; CHECK: 1 32 | ; CHECK: 2 33 | ; CHECK: 3 34 | ; CHECK: 5 35 | ; CHECK: 8 36 | ; CHECK: 13 37 | ; CHECK: 21 38 | ; CHECK: 34 39 | -------------------------------------------------------------------------------- /tests/filter.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (function sequence (first last) 18 | (if (< first last) 19 | (cons first (sequence (+ first 1) last)) ; then append next value 20 | (cons last nil))) ; else end of list 21 | 22 | (assign source (sequence 0 10)) 23 | 24 | ; Filter everything 25 | (print (filter source (function (x) false))) 26 | ; CHECK: 0 27 | 28 | ; Filter nothing 29 | (print (filter source (function (x) true))) 30 | ; CHECK: (0 1 2 3 4 5 6 7 8 9 10) 31 | 32 | ; Show only odd numbers of a sequence 33 | (print (filter source (function (x) (bitwise-and x 1)))) 34 | ; CHECK: (1 3 5 7 9) 35 | 36 | 37 | -------------------------------------------------------------------------------- /tests/forloop.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Parameter are constants 18 | (for i 3 9 1 19 | (print i)) 20 | 21 | ; CHECK: 3456789 22 | 23 | ; Negative loop index 24 | (for i 7 0 -1 25 | (print i)) 26 | 27 | ; CHECK: 76543210 28 | 29 | ; Different step size 30 | (for i 1 9 2 31 | (print i)) 32 | 33 | ; CHECK: 13579 34 | 35 | ; Parameters are variables 36 | (assign start 1) 37 | (assign end 13) 38 | (assign step 2) 39 | (for j start end step 40 | (print j)) 41 | 42 | ; CHECK: 135791113 43 | 44 | ; Parameters are expressions 45 | (for j (+ start 7) (+ end 3) (+ step 1) 46 | (print j)) 47 | 48 | ; CHECK: 81114 49 | 50 | ; Nested loop 51 | (for i 65 78 1 52 | (for j 0 4 1 53 | ($printchar (+ i j)))) 54 | 55 | ; CHECK: ABCDEBCDEFCDEFGDEFGH 56 | -------------------------------------------------------------------------------- /tests/gc.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; 18 | ; Garbage collector test. 19 | ; In the automated configuration, this ensures the program runs to completion, 20 | ; but can't ensure it frees everything. To verify this completely, I enable 21 | ; GC logs in runtime.lisp, then manually analyze the sequence of allocs/frees. 22 | ; 23 | 24 | ; Hold references to these in global variables 25 | (assign a '(1 2 (99 98 97 96) 4)) ; Nested list, needs to recurse 26 | (assign b '(5 6 7 8)) 27 | 28 | (function foo () 29 | (let ((c '(9 10)) (d '(11 12))) ; Reference on the stack, won't be collected 30 | ($gc) ; This shouldn't free anything 31 | (let ((g '(13 14 15 16))) ; If c or d were incorrectly freed, this would clobber 32 | (print c) ; CHECK: (9 10) 33 | (print d)))) ; CHECK: (11 12) 34 | 35 | (foo) 36 | ($gc) ; We should get element 'c', 'd', and 'g' back now 37 | 38 | (assign e '(17 18 19 20 21 22 23 24)) ; This will take the space that c, d, and g formerly took 39 | 40 | (assign f '(25 26 27 28)) ; Allocate a new block from the wilderness 41 | 42 | (print a) ; CHECK: (1 2 (99 98 97 96) 4) 43 | (print b) ; CHECK: (5 6 7 8) 44 | (print e) ; CHECK: (17 18 19 20 21 22 23 24) 45 | (print f) ; CHECK: (25 26 27 28) 46 | -------------------------------------------------------------------------------- /tests/gcloop.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Extended GC test, should repeatedly free up nodes. Make sure there isn't 18 | ; an eventual leak. Need to modify testbench.v to run infinitely and enable 19 | ; gclogs to ensure the same number of objects are freed each gc. 20 | (while true 21 | (cons 1 2)) 22 | -------------------------------------------------------------------------------- /tests/getbp_bug.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | 18 | (function foo (a b) 19 | (print b)) 20 | 21 | (foo (getbp) 5) ; CHECK: 5 22 | 23 | ; When the bug was present, it printed 0 24 | -------------------------------------------------------------------------------- /tests/hello.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ($printstr "Hello World") ; CHECK: Hello World 18 | -------------------------------------------------------------------------------- /tests/list.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; This test validates basic primitives for list access and construction 18 | 19 | (assign a '(1 2 3 4 5 6)) 20 | 21 | (print (length a)) ; CHECK: 6 22 | (print (nth a 0)) ; CHECK: 1 23 | (print (nth a 1)) ; CHECK: 2 24 | (print (nth a 2)) ; CHECK: 3 25 | (print (nth a 3)) ; CHECK: 4 26 | (print (nth a 4)) ; CHECK: 5 27 | (print (nth a 5)) ; CHECK: 6 28 | (print (nth a 6)) ; CHECK: 0 29 | 30 | (print (length nil)) ; CHECK: 0 31 | (print (nth nil)) ; CHECK: 0 32 | 33 | (assign b '(7 8)) 34 | (print b) ; CHECK: (7 8) 35 | 36 | ; Append atom 37 | (print (append b 9)) ; CHECK: (7 8 9) 38 | 39 | ; Append list 40 | (print (append b '(10 11 12))) ; CHECK: (7 8 10 11 12) 41 | 42 | ; Append to nil list. 43 | (print (append nil '(13 14 15))) ; CHECK: (13 14 15) 44 | 45 | (print (append '(16 17 18) nil)) ; CHECK (16 17 18) 46 | (print (append '(19) 20)) ; CHECK (19 20) 47 | (print (append '(21) '(22))) ; CHECK (21 22) 48 | 49 | 50 | (assign foo 24) 51 | (print (list 25 26 foo)) ; CHECK: (25 26 24) 52 | 53 | (print (reverse '(27 28 29 30 31))) 54 | ; CHECK: (31 30 29 28 27) 55 | 56 | ; 57 | ; Test dot notation for creating cons cells directly 58 | ; 59 | (assign a '(65 . 66)) 60 | (print (first a)) ; CHECK: 65 61 | (print (second a)) ; CHECK: 66 62 | 63 | (assign b '((12 . 22) . (47 . 59))) 64 | (print (first (first b))) ; CHECK: 12 65 | (print (second (first b))) ; CHECK: 22 66 | (print (first (second b))) ; CHECK: 47 67 | (print (second (second b))) ; CHECK: 59 68 | 69 | ; 70 | ; setfirst/setnext 71 | ; 72 | (assign foo '(0 . 0)) 73 | (setfirst foo 61) 74 | (print foo) ; CHECK: (61) 75 | (setnext foo '(65 . 0)) 76 | (print foo) ; CHECK: (61 65) 77 | 78 | ; 79 | ; Test c[ad]+r operations 80 | ; 81 | (assign test1 '(70 (71 (72 73 74) 75) 76)) 82 | (assign test2 '(77 . 78)) 83 | 84 | (print (car test2)) ; CHECK: 77 85 | (print (cdr test2)) ; CHECK: 78 86 | 87 | (print (car test1)) ; CHECK: 70 88 | (print (cdr test1)) ; CHECK: ((71 (72 73 74) 75) 76) 89 | (print (cadr test1)) ; CHECK: (71 (72 73 74) 75) 90 | (print (caadr test1)) ; CHECK: 71 91 | (print (cadadr test1)) ; CHECK: (72 73 74) 92 | (print (caadadr test1)) ; CHECK: 72 93 | 94 | ; 95 | ; find-string 96 | ; 97 | (print (find-string "abcdefghij" "abc")) ; CHECK: 0 98 | (print (find-string "habcdefghi" "abc")) ; CHECK: 1 99 | (print (find-string "hiabcdefgh" "abc")) ; CHECK: 2 100 | (print (find-string "abcdefghij" "cdg")) ; CHECK: -1 101 | 102 | ; Partial match and restart 103 | (print (find-string "abcdcdefgh" "cde")) ; CHECK: 4 104 | 105 | ; Hit end of haystack before match 106 | (print (find-string "abcdefghij" "hijk")) ; CHECK: -1 107 | 108 | ; Edge cases, not valid input 109 | (print (find-string nil "hijk")) ; CHECK: -1 110 | (print (find-string "abc" nil)) ; CHECK: 0 111 | (print (find-string nil nil)) ; CHECK: -1 112 | 113 | ; 114 | ; sub-list 115 | ; 116 | (assign source '(90 91 92 93 94 95 96 97 98 99)) 117 | 118 | (print (sub-list source 0 10)) ; CHECK: (90 91 92 93 94 95 96 97 98 99) 119 | (print (sub-list source 1 10)) ; CHECK: (91 92 93 94 95 96 97 98 99) 120 | (print (sub-list source 1 8)) ; CHECK: (91 92 93 94 95 96 97 98) 121 | (print (sub-list source 2 3)) ; CHECK: (92 93 94) 122 | (print (sub-list source 5 1)) ; CHECK: (95) 123 | (print (sub-list source 11 5)) ; CHECK: 0 124 | (print (sub-list nil 2 5)) ; CHECK: 0 125 | (print (sub-list source 0 0)) ; CHECK: 0 126 | -------------------------------------------------------------------------------- /tests/map-reduce.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (function sum (a b) 18 | (+ a b)) 19 | 20 | (function square (a) 21 | (* a a)) 22 | 23 | (function sum-of-squares (values) 24 | (reduce (map values square) sum)) 25 | 26 | (print (map '(5 7 9) square)) ; CHECK: (25 49 81) 27 | (print (map nil square)) ; CHECK: 0 28 | 29 | (print (reduce '(1) sum)) ; CHECK: 1 30 | (print (reduce '(1 2) sum)) ; CHECK: 3 31 | (print (reduce '(1 2 3) sum)) ; CHECK: 6 32 | (print (reduce '(1 2 3 4) sum)) ; CHECK: 10 33 | (print (reduce nil sum)) ; CHECK: 0 34 | 35 | (print (sum-of-squares '(2))) ; CHECK: 4 36 | (print (sum-of-squares '(3 4))) ; CHECK: 25 37 | (print (sum-of-squares '(5 6 7))) ; CHECK: 110 38 | (print (sum-of-squares '(8 9 10 11))) ; CHECK: 366 39 | (print (sum-of-squares nil)) ; CHECK: 0 40 | (print (sum-of-squares '())) ; CHECK: 0 41 | -------------------------------------------------------------------------------- /tests/match-fail.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; When changing the test harness, call this to ensure it catches the error 18 | ; 19 | ; $ python3 runtests.py match-fail.lisp 20 | ; FAIL: line 27 expected string Hello was not found 21 | ; searching here:HALTED 22 | 23 | 24 | ($printstr "Hello") 25 | ($printchar 10) 26 | ($printstr "World") 27 | 28 | ; check strings must be matched in order. Even though both occur, there 29 | ; isn't a Hello after world, so this should fail on the second check. 30 | ; CHECK: World 31 | ; CHECK: Hello 32 | -------------------------------------------------------------------------------- /tests/math.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Use variables in these expressions rather than constants so the 18 | ; optimizer doesn't remove the operations. 19 | (assign NEG -7) 20 | (assign POS 23) 21 | 22 | ; Builtin operators 23 | (print (+ POS NEG)) ; CHECK: 16 24 | (print (- POS NEG)) ; CHECK: 30 25 | (print (> 23 POS)) ; CHECK: 0 26 | (print (> 24 POS)) ; CHECK: 1 27 | (print (< 23 POS)) ; CHECK: 0 28 | (print (< 22 POS)) ; CHECK: 1 29 | (print (>= 22 POS)) ; CHECK: 0 30 | (print (>= 23 POS)) ; CHECK: 1 31 | (print (>= 24 POS)) ; CHECK: 1 32 | (print (<= 24 POS)) ; CHECK: 0 33 | (print (<= 23 POS)) ; CHECK: 1 34 | (print (<= 22 POS)) ; CHECK: 1 35 | (print (= 22 POS)) ; CHECK: 0 36 | (print (= 23 POS)) ; CHECK: 1 37 | (print (<> 22 POS)) ; CHECK: 1 38 | (print (<> 23 POS)) ; CHECK: 0 39 | (print (bitwise-and NEG POS)) ; CHECK: 17 40 | (print (bitwise-or 64 POS)) ; CHECK: 87 41 | (print (bitwise-xor POS 15)) ; CHECK: 24 42 | (print (rshift POS 1)) ; CHECK: 11 43 | (print (rshift POS 2)) ; CHECK: 5 44 | (print (lshift POS 1)) ; CHECK: 46 45 | (print (lshift POS 2)) ; CHECK: 92 46 | 47 | ; Runtime library functions 48 | (print (* NEG NEG)) ; CHECK: 49 49 | (print (* NEG POS)) ; CHECK: -161 50 | (print (* POS POS)) ; CHECK: 529 51 | (print (* POS NEG)) ; CHECK: -161 52 | (print (* 0 POS)) ; CHECK: 0 53 | (print (* POS 0)) ; CHECK: 0 54 | 55 | (print (/ -2317 POS)) ; CHECK: -100 56 | (print (/ -2317 NEG)) ; CHECK: 331 57 | (print (/ 2317 POS)) ; CHECK: 100 58 | (print (/ 2317 NEG)) ; CHECK: -331 59 | (print (/ POS 2317)) ; CHECK: 0 60 | (print (/ 0 POS)) ; CHECK: 0 61 | 62 | (print (mod -2319 POS)) ; CHECK: 19 63 | (print (mod -2319 NEG)) ; CHECK: -2 64 | (print (mod 2319 POS)) ; CHECK: 19 65 | (print (mod 2319 NEG)) ; CHECK: -2 66 | (print (sqrt 1902)) ; CHECK: 43 67 | 68 | (print (abs NEG)) ; CHECK: 7 69 | (print (abs POS)) ; CHECK: 23 70 | 71 | (print (equal 1 2)) ; CHECK: 0 72 | (print (equal 2 2)) ; CHECK: 1 73 | (print (equal 2 '(2))) ; CHECK: 0 74 | (print (equal '(2) '(2))) ; CHECK: 1 75 | (print (equal '(1 2 3) '(1 2 3))) ; CHECK: 1 76 | (print (equal '(1 2) '(1 2 3))) ; CHECK: 0 77 | (print (equal '(1 2 3) '(1 2))) ; CHECK: 0 78 | (print (equal '(1 (2 3)) '(1 (2 3)))) ; CHECK: 1 79 | (print (equal '((1 2) 3) '(1 (2 3)))) ; CHECK: 0 80 | (print (equal "foo" "bar")) ; CHECK: 0 81 | (print (equal "foo" "foo")) ; CHECK: 1 82 | (print (equal print print)) ; CHECK: 1 83 | (print (equal (function () 1) (function() 1))) ; CHECK: 0 84 | -------------------------------------------------------------------------------- /tests/oom.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Will run out of memory. Make sure runtime prints error. 18 | (while true 19 | (assign a (cons 1 a))) 20 | 21 | ; CHECK: OOM 22 | -------------------------------------------------------------------------------- /tests/optimizer.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2013 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; This module can verify correctness of operations that can be optimized, but not that 18 | ; they actually are optimized. That can be done by manually inspecting program.lst. 19 | ; The transformed S-Expression version of the code will show a bunch of constant prints 20 | 21 | 22 | ; 23 | ; Constant folding operations 24 | ; 25 | (print (bitwise-and (/ 30006 9781) (- 10926))) ; CHECK: 2 26 | (print (bitwise-or (- (bitwise-xor 9378 -14876)) (- 3224))) ; CHECK: -6 27 | (print (- (- (bitwise-not -6307) 12569) 25988)) ; CHECK: -32251 28 | (print (- (- (bitwise-and (/ -6162 -7804) -11603)) (+ (bitwise-not -31886) -12666))) ; CHECK: -19219 29 | (print (- (bitwise-not (- (bitwise-not (bitwise-not 9450)))))) ; CHECK: -9449 30 | (print (bitwise-not (bitwise-or (bitwise-not -27560) -23648))) ; CHECK: 5208 31 | (print (+ 8600 (- 15344))) ; CHECK: -6744 32 | (print (- (- (+ (bitwise-and -13413 -30063) 32184)))) ; CHECK: 2121 33 | (print (+ (bitwise-not 6015) (bitwise-xor (- (bitwise-xor -25330 -30116) (* 14939 -18396)) (* -1427 -20641)))) ; CHECK: -2955 34 | (print (- (bitwise-xor 15162 (* (- -537) (bitwise-not (- -2093 8550)))))) ; CHECK: -2168 35 | (print (- (/ (bitwise-not (- -6642)) (- (- 4255 -24399) (bitwise-not 6132))))) ; CHECK: 0 36 | (print (- (bitwise-and -13272 (bitwise-xor -15109 17211)))) ; CHECK: 31744 37 | (print (bitwise-not (* (bitwise-and -32697 (- -12007)) 14871))) ; CHECK: -7266 38 | (print (bitwise-xor -13890 (bitwise-or (bitwise-not (bitwise-not -28328)) (bitwise-not (- (- 16323)))))) ; CHECK: 6338 39 | (print (- (bitwise-or 4826 -26464))) ; CHECK: 25862 40 | (print (- (- (+ (- (- (bitwise-and -6319 14172)) (+ -14153 3183)) (bitwise-not (- -27588)))))) ; CHECK: -26683 41 | (print (* (/ (- -21065 12010) (bitwise-xor 15577 (bitwise-not -18429))) (- -19260))) ; CHECK: 19260 42 | (print (- (bitwise-not 28024) (bitwise-not (* (+ (bitwise-or -16256 -22043) (bitwise-not -14113)) (bitwise-not (bitwise-not (- -1821))))))) ; CHECK: 29465 43 | (print (- (/ (/ -14462 -18426) (- 14441)))) ; CHECK: 0 44 | (print (bitwise-not 31999)) ; CHECK: -32000 45 | (print (rshift (bitwise-not 416) (- 5 2))) ; CHECK: -53 46 | (print (+ (lshift 3 2) 5)) ; CHECK: 17 47 | 48 | ; 49 | ; Power of two strength reduction 50 | ; 51 | (assign a 12) 52 | (print (/ a 4)) ; CHECK: 3 53 | (print (/ a 2)) ; CHECK: 6 54 | (print (* a 8)) ; CHECK: 96 55 | (print (* a 16)) ; CHECK: 192 56 | 57 | ; Conditionals 58 | (print (if (< 5 7) 12 5)) ; CHECK: 12 59 | (print (if (< 7 5) 7 4)) ; CHECK: 4 60 | (print (if (> 3 2) 7)) ; CHECK: 7 61 | (print (if (> 2 3) 7)) ; CHECK: 0 62 | 63 | ; Logical operators 64 | (print (and 0 0 0)) ; CHECK: 0 65 | (print (and 0 0 1)) ; CHECK: 0 66 | (print (and 0 1 0)) ; CHECK: 0 67 | (print (and 0 1 1)) ; CHECK: 0 68 | (print (and 1 0 0)) ; CHECK: 0 69 | (print (and 1 0 1)) ; CHECK: 0 70 | (print (and 1 1 0)) ; CHECK: 0 71 | (print (and 1 1 1)) ; CHECK: 1 72 | 73 | (print (or 0 0 0)) ; CHECK: 0 74 | (print (or 0 0 1)) ; CHECK: 1 75 | (print (or 0 1 0)) ; CHECK: 1 76 | (print (or 0 1 1)) ; CHECK: 1 77 | (print (or 1 0 0)) ; CHECK: 1 78 | (print (or 1 0 1)) ; CHECK: 1 79 | (print (or 1 1 0)) ; CHECK: 1 80 | (print (or 1 1 1)) ; CHECK: 1 81 | 82 | (print (and (or 0 0) (or 0 0))) ; CHECK: 0 83 | (print (and (or 0 0) (or 1 0))) ; CHECK: 0 84 | (print (and (or 0 1) (or 0 0))) ; CHECK: 0 85 | (print (and (or 1 0) (or 0 1))) ; CHECK: 1 86 | 87 | (print (or (and 0 0) (and 0 0))) ; CHECK: 0 88 | (print (or (and 1 0) (and 0 0))) ; CHECK: 0 89 | (print (or (and 0 0) (and 1 0))) ; CHECK: 0 90 | (print (or (and 1 1) (and 0 0))) ; CHECK: 1 91 | (print (or (and 0 1) (and 1 1))) ; CHECK: 1 92 | -------------------------------------------------------------------------------- /tests/prime.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (function testfactor (n fact max) 18 | (if (<= fact max) 19 | (if (mod n fact) 20 | (testfactor n (+ fact 1) max) ; then: does not divide, check next 21 | false) ; else divides evenly, is not a prime 22 | 23 | true)) ; else did not find any divisors 24 | 25 | (function isprime (n) 26 | (testfactor n 2 (rshift n 1))) 27 | 28 | ; Print a list of all prime numbers below 40 29 | (for i 2 40 1 30 | (if (isprime i) 31 | (print i))) 32 | 33 | ; CHECK: 2 34 | ; CHECK: 3 35 | ; CHECK: 5 36 | ; CHECK: 7 37 | ; CHECK: 11 38 | ; CHECK: 13 39 | ; CHECK: 17 40 | ; CHECK: 19 41 | ; CHECK: 23 42 | ; CHECK: 29 43 | ; CHECK: 31 44 | ; CHECK: 37 45 | -------------------------------------------------------------------------------- /tests/runtests.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # 3 | # Copyright 2011-2016 Jeff Bush 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | import os 19 | import subprocess 20 | import sys 21 | 22 | TEST_DIR = os.path.normpath(os.path.dirname(os.path.abspath(__file__))) 23 | PROJECT_ROOT = os.path.join(TEST_DIR, '..') 24 | 25 | POSITIVE_TESTS = [ 26 | # Basic Compiler/Interpreter tests 27 | 'hello.lisp', 28 | 'scope.lisp', 29 | 'math.lisp', 30 | 'optimizer.lisp', 31 | 'conditionals.lisp', 32 | 'list.lisp', 33 | 'closure.lisp', 34 | 'tail-recurse.lisp', 35 | 'anonfunc.lisp', 36 | 'forloop.lisp', 37 | 'breakloop.lisp', 38 | 'getbp_bug.lisp', 39 | 'sequence.lisp', 40 | 41 | # Runtime library tests 42 | 'map-reduce.lisp', 43 | 'filter.lisp', 44 | 'gc.lisp', 45 | 'oom.lisp', 46 | 47 | # Sample programs 48 | 'y-combinator.lisp', 49 | 'sum-even-fib.lisp', 50 | 'zip.lisp', 51 | 'anagram.lisp', 52 | 'prime.lisp', 53 | 'fib.lisp', 54 | 'dict.lisp' 55 | ] 56 | 57 | def check_result(output, check_filename): 58 | result_offset = 0 59 | found_check_lines = False 60 | with open(check_filename, 'r') as infile: 61 | for linenum, line in enumerate(infile): 62 | chkoffs = line.find('CHECK: ') 63 | if chkoffs != -1: 64 | found_check_lines = True 65 | expected = line[chkoffs + 7:].strip() 66 | got = output.find(expected, result_offset) 67 | if got != -1: 68 | result_offset = got + len(expected) 69 | else: 70 | print('FAIL: line {} expected string {} was not found' 71 | .format(linenum + 1, expected)) 72 | print('searching here:' + output[result_offset:]) 73 | return False 74 | 75 | if not found_check_lines: 76 | print('FAIL: no lines with CHECK: were found') 77 | return False 78 | 79 | if output.find('HALTED', result_offset) == -1: 80 | print('simulation did not halt normally') 81 | return False 82 | 83 | print('PASS') 84 | 85 | return True 86 | 87 | 88 | def runtest(filename): 89 | try: 90 | # Compile test 91 | subprocess.check_call(['python3', os.path.join(PROJECT_ROOT, 'compile.py'), filename]) 92 | 93 | # Run test 94 | result = subprocess.check_output(['vvp', os.path.join(PROJECT_ROOT, 'sim.vvp')]).decode().strip() 95 | if result: 96 | check_result(result, filename) 97 | else: 98 | print('FAIL: no output') 99 | except KeyboardInterrupt: 100 | raise 101 | except: 102 | print('FAIL: exception thrown') 103 | raise 104 | 105 | 106 | def run_compile_error_test(filename, errorstr): 107 | result = subprocess.run(['python3', os.path.join(PROJECT_ROOT, 'compile.py'), filename], 108 | capture_output=True) 109 | if result.returncode != 1: 110 | print('FAIL: bad return call') 111 | 112 | if errorstr not in str(result.stdout, 'utf-8'): 113 | print('FAIL: error message not found') 114 | 115 | print('PASS') 116 | 117 | 118 | if len(sys.argv) > 1: 119 | runtest(os.path.join(TEST_DIR, sys.argv[1])) 120 | else: 121 | for filename in POSITIVE_TESTS: 122 | print(filename, end=' ') 123 | sys.stdout.flush() 124 | runtest(os.path.join(TEST_DIR, filename)) 125 | 126 | print('compile-fail.lisp', end=' ') 127 | run_compile_error_test(os.path.join(TEST_DIR, 'compile-fail.lisp'), 'Compile error: missing )') 128 | -------------------------------------------------------------------------------- /tests/scope.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | (assign foo 13) 18 | (print foo) ; CHECK: 13 19 | 20 | (function bar () ($printstr "bar")) 21 | 22 | ; Shadow global with parameter 23 | ((function (foo bar) 24 | (print foo) ; CHECK: 17 25 | (print bar) ; CHECK: 19 26 | (assign foo 23) 27 | (assign bar 29) 28 | (print foo) ; CHECK: 23 29 | (print bar)) ; CHECK: 29 30 | 17 19) 31 | 32 | (print foo) ; CHECK: 13 33 | (bar) ; CHECK: bar 34 | 35 | ; Shadow global with local variables 36 | ; Shadow local with inner scope (let) of locals 37 | ((function () 38 | (let ((foo 31) (bar 37)) 39 | (print foo) ; CHECK: 31 40 | (print bar) ; CHECK: 37 41 | (assign foo 41) 42 | (assign bar 43) 43 | (print foo) ; CHECK: 41 44 | (print bar) ; CHECK: 43 45 | (let ((foo 47) (bar 53)) 46 | (print foo) ; CHECK: 47 47 | (print bar) ; CHECK: 53 48 | (assign foo 59) 49 | (assign bar 61) 50 | (print foo) ; CHECK: 59 51 | (print bar)) ; CHECK: 61 52 | 53 | (print foo) ; CHECK: 41 54 | (print bar)) ; CHECK: 43 55 | (print foo))) ; CHECK: 13 56 | 57 | (print foo) ; CHECK: 13 58 | (bar) ; CHECK: bar 59 | 60 | ; Shadow with parameter enclosing closure 61 | ((function (foo bar) 62 | ((function() 63 | (print foo) ; CHECK: 59 64 | (print bar)))) 59 61) ; CHECK: 61 65 | 66 | (print foo) ; CHECK: 13 67 | (bar) ; CHECK: bar 68 | 69 | -------------------------------------------------------------------------------- /tests/sequence.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2017 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; The value of a sequence will be equal to the last expression 18 | (print 19 | (begin 20 | (+ 1 2) 21 | (+ 3 4) 22 | (+ 5 6))) 23 | 24 | ; CHECK: 11 -------------------------------------------------------------------------------- /tests/sum-even-fib.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2012 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; 18 | ; Modified Project Euler problem #2: Sum even fibonacci terms below 1000. 19 | ; 20 | 21 | (function sum-even-fib (a b max total) 22 | (let ((next-sum (+ a b))) 23 | (if (< next-sum max) 24 | (sum-even-fib b next-sum max 25 | (if (bitwise-and next-sum 1) 26 | total ; Odd 27 | (+ total next-sum))) ; Even 28 | total))) 29 | 30 | (print (sum-even-fib 1 1 1000 0)) ; CHECK: 798 31 | 32 | -------------------------------------------------------------------------------- /tests/tail-recurse.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; This uses tail recursion. Ensure it loops and doesn't overflow the 18 | ; stack. 19 | (function tail-recurse (n sum) 20 | (if n 21 | (tail-recurse (- n 1) (+ sum 3)) 22 | sum)) 23 | 24 | ($printdec (tail-recurse 2000)) ; CHECK: 6000 25 | -------------------------------------------------------------------------------- /tests/y-combinator.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2016 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; http://anler.me/posts/2015-09-17-recursion-aerobics.html 18 | 19 | (function Y (f) 20 | ((function (x) (x x))(function (y) (f (function (arg) ((y y) arg)))))) 21 | 22 | (function makefib (f) 23 | (function (n) 24 | (if (< n 2) 25 | n 26 | (+ (f (- n 1)) (f (- n 2)))))) 27 | 28 | (assign fib (Y makefib)) 29 | 30 | (print (fib 8)) ; CHECK: 21 31 | (print (fib 9)) ; CHECK: 34 32 | 33 | 34 | -------------------------------------------------------------------------------- /tests/zip.lisp: -------------------------------------------------------------------------------- 1 | ; 2 | ; Copyright 2011-2013 Jeff Bush 3 | ; 4 | ; Licensed under the Apache License, Version 2.0 (the "License"); 5 | ; you may not use this file except in compliance with the License. 6 | ; You may obtain a copy of the License at 7 | ; 8 | ; http://www.apache.org/licenses/LICENSE-2.0 9 | ; 10 | ; Unless required by applicable law or agreed to in writing, software 11 | ; distributed under the License is distributed on an "AS IS" BASIS, 12 | ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | ; See the License for the specific language governing permissions and 14 | ; limitations under the License. 15 | ; 16 | 17 | ; Merge two lists into a list of pairs. 18 | (function zip (a b) 19 | (if (and a b) 20 | (cons (cons (first a) (first b)) (zip (rest a) (rest b))) 21 | nil)) ; else end of list 22 | 23 | (foreach i (zip '(1 2 3 4 5) '(11 13 15 17 19)) 24 | (begin 25 | (print (first i)) 26 | (print (second i)))) 27 | 28 | ; Result should be ((1 . 11) (2 . 13) (3 . 15) (4 . 17) (5 . 19)) 29 | ; CHECK: 1 30 | ; CHECK: 11 31 | ; CHECK: 2 32 | ; CHECK: 13 33 | ; CHECK: 3 34 | ; CHECK: 15 35 | ; CHECK: 4 36 | ; CHECK: 17 37 | ; CHECK: 5 38 | ; CHECK: 19 39 | -------------------------------------------------------------------------------- /ulisp.v: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2011-2012 Jeff Bush 3 | // 4 | // Licensed under the Apache License, Version 2.0 (the "License"); 5 | // you may not use this file except in compliance with the License. 6 | // You may obtain a copy of the License at 7 | // 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // 10 | // Unless required by applicable law or agreed to in writing, software 11 | // distributed under the License is distributed on an "AS IS" BASIS, 12 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | // See the License for the specific language governing permissions and 14 | // limitations under the License. 15 | // 16 | 17 | `timescale 1us/1us 18 | 19 | module ulisp( 20 | input clk, 21 | input reset, 22 | output [11:0] register_index, 23 | output register_read, 24 | output register_write, 25 | output [15:0] register_write_value, 26 | input [15:0] register_read_value); 27 | 28 | localparam MEM_SIZE = 16'd4096; 29 | 30 | wire[15:0] data_mem_address; 31 | wire[15:0] instr_mem_address; 32 | wire[18:0] data_mem_read_value; 33 | wire[20:0] instr_mem_read_value; 34 | wire[18:0] data_mem_write_value; 35 | wire data_mem_write_enable; 36 | reg[18:0] data_core_read_value = 0; 37 | 38 | wire is_hardware_register_access = data_mem_address[15:12] == 4'b1111; 39 | assign register_index = data_mem_address[11:0]; 40 | assign register_write_value = data_mem_write_value[15:0]; 41 | assign register_write = is_hardware_register_access && data_mem_write_enable; 42 | assign register_read = is_hardware_register_access && !data_mem_write_enable; 43 | reg last_was_register_access = 0; 44 | 45 | always @* 46 | begin 47 | if (last_was_register_access) 48 | data_core_read_value = register_read_value; 49 | else 50 | data_core_read_value = data_mem_read_value; 51 | end 52 | 53 | lisp_core #(MEM_SIZE) c( 54 | .clk(clk), 55 | .reset(reset), 56 | .instr_mem_address(instr_mem_address), 57 | .instr_mem_read_value(instr_mem_read_value), 58 | .data_mem_address(data_mem_address), 59 | .data_mem_read_value(data_core_read_value), 60 | .data_mem_write_value(data_mem_write_value), 61 | .data_mem_write_enable(data_mem_write_enable)); 62 | 63 | rom #(MEM_SIZE, 21, 16, "program.hex") instr_mem( 64 | .clk(clk), 65 | .addr_i(instr_mem_address), 66 | .value_o(instr_mem_read_value)); 67 | 68 | ram #(MEM_SIZE, 19) data_mem( 69 | .clk(clk), 70 | .addr_i(data_mem_address), 71 | .value_i(data_mem_write_value), 72 | .write_i(data_mem_write_enable && !is_hardware_register_access), 73 | .value_o(data_mem_read_value)); 74 | 75 | always @(posedge clk) 76 | last_was_register_access <= is_hardware_register_access; 77 | endmodule 78 | --------------------------------------------------------------------------------