Compare commits

...

115 Commits

Author SHA1 Message Date
fde181aa66 Project: Fixed verilator warnings for fpga_sim 2024-02-26 13:12:26 +00:00
c527a053a6 Peripherals/ascii_to_HD44780_driver: Added support for the \e[H and \e[2J escape codes to clear the screen after the i2c_bootloader is done 2024-02-11 04:35:44 +00:00
aac55f7038 I2C_BOOTLOADER: Added support for error handling 2024-02-10 22:35:33 +00:00
a8c29aff9b I2C_BOOTLOADER: Several fixes and a 4.5x performance increase as well as the addition of 16bit reads from the I2C_driver 2024-02-10 19:42:18 +00:00
be402aa8f7 Project: updated copyright notices and README and fixed a few spelling mistakes 2024-02-10 15:52:13 +00:00
1966ab78b4 Peripherals/I2C: Added a CPU I2C driver and wrote a bootloader that uses that to boot from an I2C eeprom
I'm happy to have reached 200 commits and with this, version v0.3.0 is functionally ready. I still need to do a fair bit of cleanup and bug fixing though before the actual release. With this commit I added a CPU I2C driver as well as a basic arbiter to have the hardware lcd controller and the software i2c communication pass through the same I2C driver and I2C bus. I also wrote a bootloader that reads code from an i2c eeprom to make sure the hardware works.
2024-02-09 23:30:58 +00:00
1d9be44c5a Build system: renamed upload to upload_bitstream to allow for an upload_firmware in the future 2024-01-22 20:19:14 +00:00
8281c9a21f FPGA_Board/OrangeCrab_r0.2.1: Switched the GPIO 0/1 pins for I2C to the dedicated ones 2023-12-10 04:37:07 +00:00
3e66336456 Build system: Small fixes and corrected rebuild when only the verilator testbench was changed 2023-12-09 02:39:14 +00:00
65dfd21ef0 Peripherals/I2C_driver: Uncommented code to check for device acknowledgment 2023-12-09 00:53:52 +00:00
94bc6eba39 Build system: Added help text and target mrproper which also deletes downloaded source code 2023-12-08 22:10:11 +00:00
8544764612 Build system: Minor improvement and addition of license notice to one of the files 2023-12-07 19:21:31 +00:00
bc1dcacfc0 Build system: Fixed a bug with building the boot_code/ directory with a lot of make jobs 2023-12-07 18:45:29 +00:00
533f346f9b Build system: Added the ability to simulate an FPGA SoC and fixed all the warning verilator gave of the code previously used only for synthesis. 2023-12-07 16:39:04 +00:00
48249e8051 Forgot to add some of the files for the previous commit 2023-12-06 18:38:32 +00:00
b1108e375d Build system: Fixed standalone ./system/Makefile build and general Makefile improvements 2023-12-06 18:13:24 +00:00
df5b9c13ea Project: Removed some unused verilator warning restrictions and a TODO comment 2023-12-06 02:46:39 +00:00
05343864da Build system: Added a script that uses docker to test building the project on some popular linux distros 2023-12-06 01:22:07 +00:00
c1e597feba Build system: added handling for building on systems without git 2023-12-06 00:23:24 +00:00
8edafd70cf Build system: Improved the handling of seeds, moved most of the board specific build instructions to the board specific .mk file and fixed bios.asm dependencies 2023-12-05 21:46:56 +00:00
dc7c4e95f2 Boot_code/Brainfuck_compiler: revert accidental increase in the stack size 2023-12-05 03:16:21 +00:00
acc0581124 Boot_code/BIOS: Split the litedram init off to a separate file and included the brainfuck compiler in the bios as a demo for the ram. Also added code to zero out the brainfuck data in the compiler 2023-12-05 03:09:23 +00:00
2fcc521f12 Peripherals/Wishbone_memory: Rewrote the module to be more efficient, smaller and also support byte level addressing. It is correct enough now to run code out of! 2023-12-05 02:50:21 +00:00
dd1080b42c Build system: Added maximum CPU frequency to build system info and improved the way nextpnr seed is handled, fixing builds with older versions of make 2023-12-05 01:13:43 +00:00
dd50114c07 Build system: fixed adherence to the Makefile QUIET variable 2023-12-04 23:09:13 +00:00
26210be950 Peripherals/I2C_driver: Corrected the implementation of the bidirectional SDA pin, fixing the final yosys 0.35 warning 2023-12-04 22:40:53 +00:00
8fb6dadf48 Documentation: Updated README.md with the improvements in gen_litedram.sh 2023-12-04 22:32:21 +00:00
0eecfdcf40 Tools/Gen_litedram: Major improvements and cleanup including work in ensuring it is reproducible 2023-12-04 21:36:48 +00:00
8c921380bc Peripherals/BuiltinRam: Fixed high impedance warning in yosys 2023-12-04 17:04:22 +00:00
374b1946e9 Added .keep file for intentionally empty directory 2023-12-03 19:30:59 +00:00
63ea29e399 Peripherals/Memory: Added support for the litedram DDR memory controller, created a new memory map and updated all relevant code and files including the addition of rudimentary wait state support for the cpu (BIU) 2023-12-03 19:24:39 +00:00
f1dc9d8a59 Processor/Instructions: Fixed a bug where if IN executed after a microcoded instruction the cpu would go into undefined behavior 2023-11-26 00:18:15 +00:00
f07e0e7c1f Processor/Instructions: Added support for the IN <immediate> instruction. Also changed some stuff in system.v to add more devices in the IO/Memory space 2023-11-25 04:12:05 +00:00
17638d5cbd Build system: Slight improvements, randomised nextpnr rng seed and printed it to the terminal. In case timing fails running it a bunch of times can yield one value that passes. 2023-11-23 23:27:19 +00:00
aedefddb5d Project: The cpu finally works perfectly now even at full speed as far as i can tell! I made the ram and register writes synchronous which fixed the weird issues I had, then I added -abc9 to yosys so that nextpnr can actually route the cpu at full speed and increased the display fifo since the cpu is so fast now!! 2023-11-15 18:43:56 +00:00
29bc2e6d96 Project: Cleaned up some code and run the project through aspell 2023-11-15 14:37:46 +00:00
98d30a1813 Project: removed a .fst.hier file thought to be generated by gtkwave and added the type to gitignore 2023-11-15 00:32:40 +00:00
09ccce5f30 Peripherals/HD44780: Rewrote and cleaned up a lot of the driver code. Unfortunately what i think is a very weird bug in yosys is still affecting the codebase 2023-11-15 00:26:46 +00:00
0ca1da81b1 Assembly code: Fixed a bug where the compiler would print a null byte which was masked by the verilog simulators 2023-11-14 21:14:45 +00:00
2c8e8a9d9c Added simple support for \n and \r on the HD44780 driver, increased the synthesised mem to fit brainfuck_compiled.asm and made it the default. 2023-11-12 21:39:27 +00:00
189b037bdf Added proper line wrapping for HD44780 LCDs and rewrote half the driver to make it more flexible 2023-11-12 17:30:52 +00:00
618c3102d8 Fixed some dependencies on the makefiles 2023-11-12 13:30:12 +00:00
7d2cb5672f Reduced numbers to be sorted in gnome_sort.asm to fit in lcd, fixed hlt on real hardware, slowed down cpu, increased lcd fifo and with that I almost got gnome_sort.asm working perfectly on real hardware 2023-11-12 07:31:05 +00:00
e06c0eeaa0 Made the build system simplify the microcode so that yosys understands and synthesises it! Now gnome_sort.asm almost works! 2023-11-12 04:04:56 +00:00
fa62b07c14 Removed probably unnecessary high impedance case yosys was complaining about in registers.v 2023-11-12 03:13:22 +00:00
f471b305d8 Switched some assignments in decode.v to non-blocking which fixed a seemingly unrelated bug with incrementing the accumulator, added some more working test code in colored_led.asm and did some semantic changes as per yosys suggestions 2023-11-12 02:54:41 +00:00
4c130a8d63 Added back removed warnings to verilator since we have now fixed those issues 2023-11-12 00:07:33 +00:00
09b3d51015 Added statistics to place&route 2023-11-09 23:10:06 +00:00
863af26422 Forgot to add the changes to colored_led.asm from the previous commit 2023-11-09 23:08:12 +00:00
a88c420ca5 Added an I2C driver, a PCF8574 driver and an HD44780 display driver. Unfortunately this shows that even fibonacci doesn't run correctly. Nonetheless, I made colored_led.asm output text to the display! 2023-11-09 22:10:55 +00:00
e0dc7bae07 Move the diagram below some text since it looks a bit ugly this way 2023-11-07 14:40:51 +00:00
1a1634c673 Updated README, improved fpga-specific makefile options and updated the version number 2023-11-07 14:37:22 +00:00
4767a7addc Updated progress on README 2023-11-06 08:18:19 +00:00
01dcbfa7a1 The CPU works on real hardware for the first time! I added an adjustment for ram size, added control for a led and a test program for it. On the fpga board there is an actual led there that I used to verify functionality 2023-11-06 08:13:36 +00:00
30ffa1b00c Fixed a "combinatorial loop" and now if the build-in memory is reduced the design can be synthesized! 2023-11-06 05:36:04 +00:00
5ebd53b11c fixed more driver conflicts 2023-11-06 01:35:48 +00:00
ae16c79b0a Fixed another driver conflict 2023-11-05 20:18:11 +00:00
9947517693 Fixed simulation with icarus verilog and removed another driver conflict 2023-11-05 19:43:49 +00:00
4a5df9c74e Fixed another driver conflict 2023-11-05 16:23:05 +00:00
aa9b7c0a50 Removed more "conflicting driver" issues with yet more performance penalties... 2023-11-04 15:33:23 +00:00
df2975fa09 Fixed a lot of "conflicting driver" issues but I had to roll back an optimisation 2023-11-04 11:04:22 +00:00
c7ddf3fa9e More small fixes 2023-11-04 08:31:05 +00:00
694f708a32 Fixed some relatively low hanging fruit 2023-11-04 08:08:22 +00:00
934e2f5a36 Fixed a bunch of things wrong with fpga_top.v and gated off some more simulation-only code 2023-11-02 23:46:12 +00:00
08aac5c7b6 Removed some code that wasn't meant for synthesis and fixed important bug in Makefile 2023-11-02 22:19:15 +00:00
601397b7f0 Properly added fpga_top.v stuff in the build system and fixed some syntax errors 2023-11-02 22:00:07 +00:00
43f3e16ca4 Removed all instances of inout since from what i understand it's mostly synthesisable 2023-11-02 21:48:12 +00:00
36bf8f9c7a Added OrangeCrab board-specific code to connect the cpu to the outside world 2023-11-02 20:40:04 +00:00
5feee9de57 Added support to the build system for synthesising, place and routing, serialising and uploading the design to a Lattice ECP5 OrangeCrab FPGA 2023-11-02 00:29:14 +00:00
85512d5ace Last minute fix of dependencies in Makefile before release 2023-11-01 19:09:59 +00:00
b2972c9938 release v0.2.0 - Pipelined milestone 2023-11-01 06:08:12 +00:00
3ec90b1843 Added version stamp and last commit to json log 2023-11-01 06:03:53 +00:00
557d160be6 did some cleanup relating to the generation of the VALID_INSTRUCTION signal 2023-11-01 05:00:09 +00:00
3a63e916f5 Added cycles to waveform capture for icarus verilog 2023-10-31 19:32:35 +00:00
49335a2c2f Fixed a small bug in log generation and did some cleanup 2023-10-31 19:01:34 +00:00
8a62b89a13 Fixed small bug with json data reporting and improved slightly the graphs 2023-10-30 08:01:03 +00:00
cfed0b4117 Made the temporary logo a bit more centered. Also removed an incorrect line in README 2023-10-24 01:08:13 +01:00
4c28f98797 Updated the high level design overview diagram 2023-10-23 13:28:58 +01:00
d151435ac1 Removed redundant checks for enabled early instruction detection in BIU 2023-10-23 02:30:25 +01:00
ced03c48d6 Added cache flush after write, potentially fixing support for self modifying code 2023-10-23 02:09:13 +01:00
8d3b54b812 Small change from when I last worked on this and an update to the versions on the README 2023-10-21 18:38:50 +01:00
42c319d55d Lots of cleanup mainly on processor.v 2023-06-01 02:13:55 +01:00
a693b87e96 General cleanup and moved the reading of instruction parameters from a separate stage in execute to circuitry during the decode 2023-05-29 02:29:15 +01:00
af63ef1d68 Moved the decoder logic to decoder.v Now processor.v only connects the different modules 2023-05-27 23:35:00 +01:00
d2a98c02ff Removed duplicate code and improved microcode entry 2023-05-27 17:59:52 +01:00
79d598fc64 Changed slogan and cleaned up some small pieces of code 2023-05-23 16:18:33 +01:00
0bf00df07c Fixed clock cycle and instruction counter overflow 2023-05-23 09:27:46 +01:00
35a5a9ada2 Added more data to a test program 2023-05-22 22:33:00 +01:00
6c146098ee Removed useless code from cache_fill_and_empty.asm 2023-05-21 03:01:24 +01:00
e74d73ed58 Added reporting of branches on the stat json files and improved the plotting script 2023-05-21 03:00:27 +01:00
3dd2ff59ea Added 2 more test programs, 2 new instructions and fixed a bug in CMP 2023-05-21 01:48:50 +01:00
021dd06e9a Added support for some more instructions, fixed a bug in CMP and also added a program that uses them 2023-05-19 17:59:20 +01:00
64f5da82b0 Improved cache utilisation plotting tool 2023-05-18 20:16:31 +01:00
1b510e4781 Made the size of the cache variable 2023-05-18 11:21:27 +01:00
7db70d79ff Made execute unit start at a state transition of a signal from the decoder thus allowing for an IPC of 0.99 !! 2023-05-17 21:30:21 +01:00
90f63b525d Made the decode unit able to continuously decode (simple) instructions if BIU allows it 2023-05-17 20:09:38 +01:00
30c3deca37 Made the execute unit signal the end of execution by a state change rather than the state of a signal to allow for one cycle instructions 2023-05-17 11:05:20 +01:00
53e9d371d7 Fully optimised BIU. Now it can instantly deliver instructions back to back 2023-05-16 18:07:28 +01:00
f914d1ec8f Cleaned up processor.v a bit 2023-05-16 16:29:48 +01:00
aca3357cda Fixed README formatting error 2023-05-16 14:06:17 +01:00
97912b1a29 Fixed bug found by icarus verilog and added outdated notice to README 2023-05-16 13:59:16 +01:00
bfa576e2a0 Cleaned up the interface between BIU and the processor 2023-05-16 13:33:08 +01:00
07d2a80b2e Added code to record statistics and a tool to plot them 2023-05-14 16:06:33 +01:00
df342467c7 Saved a clock cycle from microcode starts and added info in decode to allow saving a cycle on almost every instruction 2023-05-13 13:45:15 +01:00
00aa828ddc Improved parallelism 2023-05-13 10:52:44 +01:00
fe0426a77b Made execute unit run in parallel with everything else. Still not parallel for most of the time though 2023-05-13 06:51:35 +01:00
7151d5634f Fixed bug that prevented Icarus Verilog from simulating correctly 2023-05-11 19:55:47 +01:00
539fb8416b Fixed copyright notices, did some major cleanup and bumped README's versions 2023-05-11 16:28:10 +01:00
a8ab6b2dc7 Separated the execution unit from decode 2023-05-11 12:22:49 +01:00
7724e5f383 Removed deprecated BIU_NEXT_POSITION 2023-05-10 08:53:29 +01:00
e4ef199b83 Fixed a memory corruption bug 2023-05-10 08:35:14 +01:00
7e612bb701 made BIU snoop into the processor to deliver new instructions faster and fixed some bugs 2023-05-10 08:31:14 +01:00
c854818d6d Tightened up write timing 2023-05-10 04:43:09 +01:00
b7bfbd4e33 Improved BIU performance and debug messages 2023-05-10 04:05:56 +01:00
da51dd6da7 First draft of a bus interface unit in an effort to make the CPU pipelined. Currently supports code prefetching 2023-05-07 13:34:15 +01:00
64 changed files with 6468 additions and 1467 deletions

19
.gitignore vendored
View File

@ -5,12 +5,19 @@
*.bf.asm
*.swp
*.memdump
boot_code/brainfuck_interpreted.bin
boot_code/brainfuck_interpreted.txt
boot_code/brainfuck_mandelbrot.bin
boot_code/brainfuck_mandelbrot.txt
boot_code/brainfuck_compiled.bin
boot_code/brainfuck_compiled.txt
*.json
*.dfu
*.bit
*.fst.hier
abc.history
boot_code/*.bin
boot_code/*.txt
boot_code/*.stxt
system/boot_code.bin
system/boot_code.txt
system/obj_dir/
system/simplified_ucode.txt
system/build/
tools/*svg
system/external_ip/litedram_core_ecp5_phy.v
system/external_ip/litedram_core_ecp5_phy_sim.v

View File

@ -1,6 +1,6 @@
# This file is part of the 9086 project.
#
# Copyright (c) 2023 Efthymios Kritikos
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -21,7 +21,8 @@ VERILATOR_BIN=system/obj_dir/Vsystem
BOOT_CODE=boot_code/brainfuck_mandelbrot.txt
GTKWSAVE=./gtkwave_savefile.gtkw
MICROCODE=system/ucode.txt
BOOTABLES=boot_code/brainfuck_compiled.txt boot_code/brainfuck_interpreted.txt ${BOOT_CODE}
BOOTABLES=boot_code/brainfuck_compiled.txt boot_code/brainfuck_interpreted.txt boot_code/pipeline_ideal.txt boot_code/fibonacci.txt boot_code/gnome_sort.txt boot_code/cache_fill_and_empty.txt ${BOOT_CODE} boot_code/colored_led.txt boot_code/bios.stxt boot_code/i2c_bootloader.stxt
PRINT_PATH_PREFIX=.
NO_ASM=1
include common.mk
@ -29,21 +30,63 @@ include common.mk
.PHONY: ${BOOTABLES}
.PHONY: ${subst .txt,.bin,${BOOTABLES}}
${BOOTABLES} ${subst .txt,.bin,${BOOTABLES}} :
${Q}make ${MAKEOPTS} -C boot_code $(subst boot_code/,,$@)
${BOOTABLES} ${subst .stxt,.bin,${subst .txt,.bin,${BOOTABLES}}} :
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code $(subst boot_code/,,$@)
boot_code/%.txt:
${Q}make ${MAKEOPTS} -C boot_code $(subst boot_code/,,$@)
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code $(subst boot_code/,,$@)
.PHONY:${SYSTEM_VVP}
${SYSTEM_VVP}:
${Q}make ${MAKEOPTS} -C system system.vvp
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system system.vvp
.PHONY:${VERILATOR_BIN}
${VERILATOR_BIN}:
${Q}make ${MAKEOPTS} -C system obj_dir/Vsystem
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system obj_dir/Vsystem
.PHONY: clean
clean:
${Q}make ${MAKEOPTS} -C system clean
${Q}make ${MAKEOPTS} -C boot_code clean
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system clean
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code clean
.PHONY: mrproper
mrproper: clean
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system mrproper
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code mrproper
.PHONY: upload_bitstream
upload_bitstream: boot_code/i2c_bootloader.stxt
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system upload_bitstream
.PHONY: upload_bootrom
upload_bootrom: boot_code/brainfuck_mandelbrot.bin
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system upload_bootrom
.PHONY: fpga_sim
fpga_sim: boot_code/i2c_bootloader.stxt
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system fpga_sim
.PHONY: help
help:
@echo 'Simulation targets:'
@echo ' - No target will start a simulation with the default'
@echo ' program loaded to memory'
@echo ' boot_code/[name].run - Start a simulation and load memory with the'
@echo ' assembled code from boot_code/[name].asm'
@echo ' boot_code/[name].wave - like the above but write trace file and start'
@echo ' gtkwave with it'
@echo ' boot_code/[name].disas - assemble and show the disassembly of the binary'
@echo ''
@echo 'Synthesis targets:'
@echo ' upload_bitstream - Build a bitstream for the board selected in'
@echo ' common.mk and upload it if possible'
@echo ' upload_bootrom - Build the rom file and upload it to an I2C rom'
@echo ' Currently only the MiniPro programmer is supported'
@echo ' fpga_sim - Simulate the SoC that gets build for the configured'
@echo ' fpga board'
@echo ''
@echo 'Cleaning targets:'
@echo ' clean - Delete all non-source files generated by the build'
@echo ' system'
@echo ' mrproper - clean + delete downloaded external source IP files'

View File

@ -1,7 +1,7 @@
<img width="186" height="70" style=" margin: 10px 0px 10px 10px;" alt="9086 logo" src="readme_files/9086_design1.svg">
A CPU that aims to be binary compatible with the 8086 and with as many optimisations as possible
A CPU that aims to be binary compatible with the 8086 ISA, focused on optimisation and flexibility.
### Progress
@ -10,28 +10,67 @@ A CPU that aims to be binary compatible with the 8086 and with as many optimisat
* [X] Is Turing complete
* [ ] Can boot up MS-DOS / FreeDOS
* [ ] Is completely binary compatible
* [ ] Is pipelined
* [X] Is pipelined
* [ ] Is Out of Order
* [ ] Is superscalar
* [ ] Has been successfully synthesized
* [X] Has been successfully synthesized
* [ ] Has a comprehensive testing framework
### Simulating it
Both Verilator and Icarus Verilog can be used for simulation. You can select which one you want with the SIM variable on [common.mk](./common.mk)
Specifically this list shows the software needed and the versions used during development (other versions should work as well)
Both Verilator and Icarus Verilog can be used for simulation. You can select which one you want with the SIM variable on [./common.mk](./common.mk).
This list shows the software needed and the versions used during development :
* Icarus Verilog : version 11.0 OR **(preferred)** Verilator : 5.006
* Icarus Verilog : version 12.0 OR **(preferred)** Verilator : 5.018
* bin86 : 0.16.21
* GNU Make : 4.4.1
* xxd : 2022-01-14
* POSIX coreutils : GNU coreutils 9.1
* xxd : 2023-10-25
* POSIX coreutils : GNU coreutils 9.4
After that you can run `make` on the top level directory and it should build everything and start the simulation
### Synthesis and bitstream creation for FPGAs
You need to set FPGA\_BOARD in [./common.mk](./common.mk) to the name of a directory inside [./system/fpga\_config/](system/fpga_config/). You should also check inside your board directory for config.mk for further board-specific configuration options like the model of I2C boot rom (if any). Then you can run `make upload_bitstream` in the top level directory and it should create the bitstream and upload it to the fpga. Depending on the board you might need to run `make upload_bootrom` to upload the boot code to an I2C eeprom.
These are the currently supported FPGA boards:
* OrangeCrab r0.2.1
This list shows the software needed and the versions used during development :
* yosys : 0.37
* bin86 : 0.16.21
* GNU Make : 4.4.1
* xxd : 2023-10-25
* POSIX coreutils : GNU coreutils 9.4
Additionally, for ECP5 FPGAs:
* prjtrellis : 1.4 ( database commit 4dda149b9e4f1753ebc8b011ece2fe794be1281a )
* nextpnr : 0.6
Additionally, for FPGAs using the [foboot](https://github.com/im-tomu/foboot) bootloader
* dfu-util : 0.11
Additionally, for boards that require an I2C eeprom to boot from
* minipro : 0.6 - ( git commit a227bce77d1b592785558e0af58ae2b0b97d4a23 )
Additionally, if you need a DRAM/DDR controller, the project supports litedram but all the dependencies
needed to build it are downloaded automatically by the appropriate script.
### High level design overview
<img width="700" style=" margin: 10px 0px 10px 10px;" alt="9086 logo" src="readme_files/9086_overview.svg">
### License
All parts of this project are licensed under the GNU General Public License version 3 or later
### License and Copyright
All parts of this project and files in this repository are licensed under the GNU General Public License version 3 or later
Efthymios Kritikos is the copyright owner for all files except the following:
| File | Copyright owner | Original license |
| :--------------------------------------------------------: | :-------------: | :--------------: |
| system/fpga\_config/OrangeCrab\_r0.2.1/pin\_constraint.pcf | Greg Davill | MIT |
### Version names
The version name consist of three numbers:
@ -41,3 +80,4 @@ The version name consist of three numbers:
1. Patch level
For example v1.3.2 aims to support 80186 code, is on the fourth milestone and has 2 bug fixes since the milestone was reached.
A "-dev" suffix denotes that the code is in the process to become that version, so in-between that and the previous.

286
boot_code/LiteDram_init.asm Normal file
View File

@ -0,0 +1,286 @@
litedram_init:
mov bx,#initdram_txt
call print
WAIT_PLL:
inw #0x20
test al,#0x04
jz WAIT_PLL
;;; DO ALL INIT STUFF ;;;
;////sdram_software_control_on///
MOV BX,#0x0000
MOV AX,#0x000E
call sdram_dfii_control_write
;/////////////////////////////////
MOV BX,#0x0000
MOV AX,#0x0000
CALL ddrctrl_init_done_write
mov bx,#0x0000
mov ax,#0x0000
call ddrctrl_init_error_write
mov bx,#0x0000
mov ax,#0x000C
call sdram_dfii_control_write
MOV DL,#0xF0
DELAY11:
MOV AX,#0xF000
DELAY1:
INC AX
JNZ DELAY1
INC DL
JNZ DELAY11
MOV BX,#0x0000
MOV AX,#0x0000
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0000
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x000E
call sdram_dfii_control_write
MOV DL,#0xF0
DELAY21:
MOV AX,#0xF000
DELAY2:
INC AX
JNZ DELAY2
INC DL
JNZ DELAY21
MOV BX,#0x0000
MOV AX,#0x0200
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0002
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x000F
call command_p0
MOV BX,#0x0000
MOV AX,#0x0000
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0003
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x000F
call command_p0
MOV BX,#0x0000
MOV AX,#0x0006
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0001
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x000F
call command_p0
MOV BX,#0x0000
MOV AX,#0x0320
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0000
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x000F
call command_p0
MOV DL,#0xF0
DELAY31:
MOV AX,#0xF000
DELAY3:
INC AX
JNZ DELAY3
INC DL
JNZ DELAY31
MOV BX,#0x0000
MOV AX,#0x0400
call sdram_dfii_pi0_address_write
mov bx,#0x0000
mov ax,#0x0000
call sdram_dfii_pi0_baddress_write
mov bx,#0x0000
mov ax,#0x0003
call command_p0
;////sdram_software_control_off///
MOV BX,#0x0000
MOV AX,#0x0001
call sdram_dfii_control_write
;////////////////////////////////
;Signify end of init
MOV BX,#0x0000
MOV AX,#0x0001
CALL ddrctrl_init_done_write
;;;;;;;;;; PROBABLY NOT NECESSARY
MOV DL,#0xF0
DELAY41:
MOV AX,#0xF000
DELAY4:
INC AX
JNZ DELAY4
INC DL
JNZ DELAY41
;;; CHECK ;;;
inw #0x20
test al,#0x01
jz failram
mov bx,#OK_txt
call print
JMP FINISHED_DDR
failram:
mov bx,#FAIL_txt
call print
mov bx,#NOT_RDY_txt
call print
inw #0x20
test al,#0x02
jz skip_err
mov bx,#ERR_ASRT_txt
call print
skip_err:
inw #0x20
test al,#0x04
jnz skip_pll
mov bx,#PLL_ERR_txt
call print
skip_pll:
hlt
FINISHED_DDR:
MOV DI,#0x0700
MOV AX,#0xAAAA
MOV [DI],AX
MOV AX,#0x6666
MOV AX,[DI]
CMP AX,#0xAAAA
JNZ FAILED
MOV BX,#MEMTEST_PASS
CALL print
RET
FAILED:
MOV BX,#MEMTEST_FAIL
CALL print
HLT
;;; HELPER FUNCTION
command_p0:
call WISHBONE_SET_DATA
MOV AX,#0x0401 ;ORIG=0x1804L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
MOV AX,#0x0001
MOV BX,#0x0000
call WISHBONE_SET_DATA
MOV AX,#0x0402 ;ORIG=0x1808L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
#AX: Lower 16 bits data
#BX: Upper 16 bits data
sdram_dfii_pi0_address_write:
call WISHBONE_SET_DATA
MOV AX,#0x0403 ;ORIG=0x180cL
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
sdram_dfii_pi0_baddress_write:
call WISHBONE_SET_DATA
MOV AX,#0x0404 ;ORIG=0x1810L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
sdram_dfii_control_write:
call WISHBONE_SET_DATA
MOV AX,#0x0400 ;ORIG=0x1800L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
ddrctrl_init_done_write:
call WISHBONE_SET_DATA
MOV AX,#0x0000 ;ORIG=0x0L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
ddrctrl_init_error_write:
call WISHBONE_SET_DATA
MOV AX,#0x0001 ;ORIG=0x4L
CALL WISHBONE_SET_ADDRESS
CALL DO_WRITE_TRANSACTION
ret
;
DO_WRITE_TRANSACTION:
mov ax,#0x01
outw #0x46
mov bl,#0x01
WB_WRITE_LOOP:
inc bl
jz WB_WRITE_TIMEOUT
inw #0x44
test al,#0x01
jz WB_WRITE_LOOP
test al,#0x04
jnz WB_WRITE_ERR
ret
WB_WRITE_TIMEOUT:
mov bx,#WISHBONE_TIMEOUT_txt
call print
hlt
WB_WRITE_ERR:
mov bx,#WISHBONE_ERROR_txt
call print
hlt
#AX: address
WISHBONE_SET_ADDRESS:
outw #0x44
ret
#AX: Lower 16bits
#BX: Upper 16bits
WISHBONE_SET_DATA:
outw #0x40
MOV AX,BX
outw #0x42
ret
initdram_txt: .ASCII 'Init LiteDram: \0'
OK_txt: .ASCII 'OK\n\0'
PLL_ERR_txt: .ASCII 'PLL_ERR \0' ; PLL_ERR: pll_lock is not asserted
ERR_ASRT_txt: .ASCII 'ERR_ASRT \0' ; ERR_ASRT: init_error is asserted
NOT_RDY_txt: .ASCII 'NOT_RDY \0' ; NOT READY: init_done is not asserted
FAIL_txt: .ASCII 'FAIL\n\0'
WISHBONE_TIMEOUT_txt: .ASCII 'FAIL\nWISHBONE TIMEOUT\0'
WISHBONE_ERROR_txt: .ASCII 'FAIL\nWISHBONE ERROR\0'
MEMTEST_PASS: .ASCII 'MEMTEST PASSED\n\0'
MEMTEST_FAIL: .ASCII 'MEMTEST FAILED\n\0'

View File

@ -1,15 +1,42 @@
SOURCE=brainfuck_interpreted.asm brainfuck_compiled.asm brainfuck_mandelbrot.asm
BINARIES=$(subst .asm,.txt,${SOURCE})
# This file is part of the 9086 project.
#
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
PRINT_PATH_PREFIX=./
SOURCE_FULL=brainfuck_interpreted.asm brainfuck_compiled.asm brainfuck_mandelbrot.asm pipeline_ideal.asm fibonacci.asm gnome_sort.asm cache_fill_and_empty.asm colored_led.asm
SOURCE_SHORT=bios.asm i2c_bootloader.asm
BINARIES=$(subst .asm,.txt,${SOURCE_FULL}) $(subst .asm,.stxt,${SOURCE_SHORT})
BUILD_FILES=${BINARIES}
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE})
BUILD_FILES+=$(subst .asm,.fst,${SOURCE})
BUILD_FILES+=$(subst .asm,.bin,${SOURCE})
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.fst,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.bin,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.json,${SOURCE_FULL} ${SOURCE_SHORT})
all: ${BINARIES}
brainfuck_interpreted.bin: brainfuck_interpreter_v0.asm hello_9086.bf.asm dos_layer.asm
brainfuck_compiled.bin: brainfuck_compiler_v1.asm hello_9086.bf.asm dos_layer.asm
brainfuck_mandelbrot.bin: brainfuck_compiler_v1.asm mandelbrot.bf.asm dos_layer.asm
colored_led.bin: dos_layer.asm
bios.bin: LiteDram_init.asm brainfuck_compiler_v1.asm hello_9086.bf.asm dos_layer.asm
i2c_bootloader.bin: LiteDram_init.asm
fibonacci.bin: helpers.asm
gnome_sort.bin: helpers.asm
%.bf.asm:%.bf
${Q}sed "s/[a-zA-Z\* ]//g;/^$$/d;s/^/.ASCII '/;s/\$$/'/" "$^" > $@
@ -20,3 +47,5 @@ include ../common.mk
clean:
$(call QUIET_CLEAN,boot_code)
${Q}rm -f $(BUILD_FILES) *.bf.asm
mrproper:

31
boot_code/bios.asm Normal file
View File

@ -0,0 +1,31 @@
.org 0xF800
mov sp,#STACK
call litedram_init
call INIT_INT_VECT_TABLE
INCLUDE brainfuck_compiler_v1.asm
prog:
INCLUDE hello_9086.bf.asm
INCLUDE dos_layer.asm
include LiteDram_init.asm
print:
mov al,[bx]
cmp al,#0
je print_exit
out byte #0xA5
inc bx
jmp print
print_exit:
ret
.BLKB 18 ; Using the text as stack space for the compiled program
STACK: ; brainfuck_mandelbrot depends on stack being at the end
.ORG 0xFFF0
MOV AX,#0xF800
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

View File

@ -1,15 +1,22 @@
; Interrupt table and routines
INCLUDE dos_layer.asm
org 0x100
INCLUDE brainfuck_compiler_v1.asm
output_program:
org 0xF800
mov sp,#SMALL_STACK
call INIT_INT_VECT_TABLE
INCLUDE brainfuck_compiler_v1.asm
SMALL_STACK:
INCLUDE dos_layer.asm
prog:
INCLUDE hello_9086.bf.asm
output_program:
.ORG 0xFFF0
MOV AX,#0x0100
MOV AX,#0xF800
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

View File

@ -2,7 +2,7 @@
;
; This file is part of the 9086 project.
;
; Copyright (c) 2023 Efthymios Kritikos
; Copyright (c) 2024 Efthymios Kritikos
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
@ -17,7 +17,9 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
mov sp,#STACK
; 0x0000-0x0100 int vector 0x0100-0x0700 data 0x0700-0xC000 program data
mov sp,#STACK_COMPILER
mov bx,#bootup_msg
mov ah,#0x02
print1:
@ -27,17 +29,27 @@ inc bx
cmp dl,#0x0A
jne print1
MOV DI,#0x0200
MOV AX,#0x0000
MOV bl,#0x00
CLEAR:
STOSW
INC BL
JNZ CLEAR
mov bx,#compiling
mov ah,#0x02
print2:
mov dl,[bx]
cmp dl,#0
je exit
int #0x21
inc bx
cmp dl,#0
jne print2
jmp print2
exit:
MOV SI,#prog
MOV DI,#output_program
MOV DI,#0x0700
;CL: write concat CH: move concat
MOV CX,#0
JMP COMPILE ; Moving some functions above the main switch to make shot jumps work
@ -146,8 +158,9 @@ jne print3
MOV AL,#0xF4 ; hlt
MOV [DI],AL
MOV BX,#DATA
MOV AX,#output_program
; From 0x100 its free but i'll do 0x200 in case it start writing earlier
MOV BX,#0x0200
MOV AX,#0x0700
JMP AX
;;;;;;;;; . ;;;;;;;;;
@ -248,18 +261,19 @@ MOV AL,#0x43 ; inc %bx
STOSB
JMP MOVES_FLUSHED
MOVES_ONE_LEFT:
MOV AL,#0x4b ; dec %bx
STOSB
JMP MOVES_FLUSHED
MOVES_FLUSHED:
MOV CH,#0
RET
bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n'
compiling: .ASCII 'Compiling...\0'
compiled: .ASCII '\rCompiled! \n'
DATA: .BLKB 560
.BLKB 200
STACK:
compiling: .ASCII 'Compiling...\0'
bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n'
.BLKB 6 ; Using the text as stack space for the compiled program
STACK_COMPILER: ; brainfuck_mandelbrot depends on stack being at the end

View File

@ -1,16 +1,16 @@
; Interrupt table and routines
INCLUDE dos_layer.asm
ORG 0x100
ORG 0xF000
mov sp,#STACK
call INIT_INT_VECT_TABLE
INCLUDE brainfuck_interpreter_v0.asm
.BLKB 200
STACK:
INCLUDE dos_layer.asm
prog:
INCLUDE hello_9086.bf.asm
.ORG 0xFFF0
MOV AX,#0x0100
MOV AX,#0xF000
JMP AX

View File

@ -2,7 +2,7 @@
;
; This file is part of the 9086 project.
;
; Copyright (c) 2023 Efthymios Kritikos
; Copyright (c) 2024 Efthymios Kritikos
;
; This program is free software: you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by

View File

@ -1,14 +1,22 @@
; Interrupt table and routines
INCLUDE dos_layer.asm
;I got this down to 11428 bytes
.ORG 0x100
org 0x100
output_program:
org 0xC000
mov sp,#SMALL_STACK
call INIT_INT_VECT_TABLE
INCLUDE brainfuck_compiler_v1.asm
SMALL_STACK:;Stack of compiler is at the end of file
INCLUDE dos_layer.asm
prog:
INCLUDE mandelbrot.bf.asm
output_program:
.ORG 0xFFF0
MOV AX,#0x0100
MOV AX,#0xC000
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

View File

@ -0,0 +1,33 @@
.ORG 0x0100
MOV DI,#0x2000
STOS
STOS
STOS
STOS
STOS
STOS
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
MOV CX,#0x0000
HLT
.ORG 0xFFF0
MOV AX,#0x0100
JMP AX

65
boot_code/colored_led.asm Normal file
View File

@ -0,0 +1,65 @@
.org 0xE000
mov sp,#STACK
MAIN_LOOP:
MOV DL,#0xF0
DELAY11:
MOV AX,#0x0000
DELAY1:
INC AX
JNZ DELAY1
INC DL
JNZ DELAY11
MOV AL,#0x01
out byte #0xB0
MOV SI,#RESERVED
MOV DI,#RESERVED
MOV AL,#0x68 ; 'h'
#STOSB
#MOV AL,#0x00
#MOV AL,[SI]
#MOV AH,#0x02
#MOV DL,AL
#INT #0x21
out byte #0xA5
MOV AL,#0x65
out byte #0xA5
MOV AL,#0x6c
out byte #0xA5
MOV AL,#0x6c
out byte #0xA5
MOV AL,#0x6f
out byte #0xA5
MOV AL,#0x20
out byte #0xA5
MOV DL,#0xF0
DELAY21:
MOV AX,#0x0000
DELAY2:
INC AX
JNZ DELAY2
INC DL
JNZ DELAY21
MOV AL,#0x00
out byte #0xB0
MOV AX,#0xE000
JMP AX
RESERVED: DB 0x48 ; 'H'
.BLKB 100
STACK:
#INCLUDE dos_layer.asm
.ORG 0xFFF0
MOV AX,#0xE000
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

View File

@ -1,7 +1,3 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
PRINT_INT_HANDLE:
push AX
CMP AH,#0x02
@ -14,3 +10,15 @@ MOV AL,DL
out byte #0xA5
POP AX
iret
INIT_INT_VECT_TABLE:
push AX
push DI
MOV DI,#0x0084
MOV AX,#0xFFFF
STOSW
MOV AX,#PRINT_INT_HANDLE
STOSW
POP DI
POP AX
RET

39
boot_code/fibonacci.asm Normal file
View File

@ -0,0 +1,39 @@
org 0xF000
mov sp,#STACK
call INIT_INT_VECT_TABLE
MOV AX,#0x1
MOV BX,#0x1
CALL PRINT_16_HEX
push bx
MAIN_LOOP:
pop bx
CALL PRINT_16_HEX
push AX
ADD AX,BX
JNC MAIN_LOOP
pop bx
MOV AH,#0x02
MOV DL,#0x0a
INT #0x21
hlt
INCLUDE dos_layer.asm
.BLKB 200
STACK:
INCLUDE helpers.asm
.ORG 0xFFF0
MOV AX,#0xF000
JMP AX

56
boot_code/gnome_sort.asm Normal file
View File

@ -0,0 +1,56 @@
.org 0xF000
mov sp,#STACK
MOV SI,#DATA
call INIT_INT_VECT_TABLE
GNOME_SORT:
CMP SI,#DATA+23
JZ GNOMED
MOV AX,[SI]
INC SI
CMP AH,AL
JAE GNOME_SORT
SWAP:
MOV BL,AL
MOV AL,AH
MOV AH,BL
DEC SI
MOV [SI],AX
CMP SI,#DATA
JZ GNOME_SORT
DEC SI
JMP GNOME_SORT
GNOMED:
MOV SI,#DATA
PRINT_LOOP:
MOV AL,[SI]
call PRINT_0_8_HEX
INC SI
CMP SI,#DATA+24
JNZ PRINT_LOOP
MOV AH,#0x02
MOV DL,#0x0a
INT #0x21
hlt
INCLUDE dos_layer.asm
DATA: DB 0x51, 0x17, 0x37, 0x5d, 0x06, 0x3f, 0x51, 0x8b
DB 0xa5, 0x33, 0x54, 0xdf, 0xae, 0xee, 0x3a, 0x18
DB 0xe9, 0xdb, 0x1f, 0x21, 0x44, 0x4f, 0x99, 0x09
.BLKB 200
STACK:
INCLUDE helpers.asm
.ORG 0xFFF0
MOV AX,#0xF000
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

93
boot_code/helpers.asm Normal file
View File

@ -0,0 +1,93 @@
;Input AX
PRINT_16_HEX:
PUSH DX
TEST AH,#0xF0
jz NOT_FIRST_NIBBLE
MOV DL,AH
CALL PRINT_HIGH
JMP SKIP1
NOT_FIRST_NIBBLE:
TEST AH,#0x0F
jz NOT_SECOND_NIBBLE
SKIP1:
MOV DL,AH
CALL PRINT_LOW
JMP SKIP2
NOT_SECOND_NIBBLE:
TEST AL,#0xF0
jz NOT_THIRD_NIBBLE
SKIP2:
MOV DL,AL
CALL PRINT_HIGH
NOT_THIRD_NIBBLE:
MOV DL,AL
CALL PRINT_LOW
PUSH AX
MOV AH,#0x02
MOV DL,#0x20
INT #0x21
POP AX
POP DX
RET
PRINT_HIGH:
AND DL,#0xF0
TEST DL,#0x80
jz NOT1
OR DL,#0x08
NOT1:
TEST DL,#0x40
jz NOT2
OR DL,#0x04
NOT2:
TEST DL,#0x20
jz NOT3
OR DL,#0x02
NOT3:
TEST DL,#0x10
jz DONE
OR DL,#0x01
DONE:
PRINT_LOW:
PUSH AX
AND DL,#0x0F
CMP DL,#0x0A
JNS LETTERS
ADD DL,#0x30
MOV AH,#0x02
INT #0x21
POP AX
RET
LETTERS:
ADD DL,#0x37
MOV AH,#0x02
INT #0x21
POP AX
RET
PRINT_0_8_HEX:
MOV DL,AL
PUSH AX
CALL PRINT_HIGH
POP AX
MOV DL,AL
CALL PRINT_LOW
PUSH AX
MOV AH,#0x02
MOV DL,#0x20
INT #0x21
POP AX
RET

View File

@ -0,0 +1,187 @@
.org 0xF800
mov sp,#STACK
call litedram_init
mov bx,#load_i2c_txt
call print
;########### SET ROM ADDRESS ############
mov al,#0x50
outb #0x61
mov ax,#0x0000 ; I2C ADDRESS
outw #0x62
mov al,#0x02 ; Write 16bit
outb #0x63
mov al,#0x00
outb #0x60
wait_send:
inb #0x62
test al,#0x02
jnz rom_fail
test al,#0x01
jnz wait_send
mov bx,#OK_loading_txt
call print
jmp read_code
rom_fail:
call rom_fail_print
;############ READ CODE ##################
read_code:
mov bx,#0xEFFF
mov di,#0x0000
rom_read_loop:
mov al,#0x07 ; Read, 8bit, ignore ack
outb #0x63
mov al,#0x00
outb #0x60
push bx
cmp di,#0x1800
jz print_10
cmp di,#0x3000
jz print_20
cmp di,#0x4800
jz print_30
cmp di,#0x6000
jz print_40
cmp di,#0x7800
jz print_50
cmp di,#0x9000
jz print_60
cmp di,#0xA800
jz print_70
cmp di,#0xC000
jz print_80
cmp di,#0xD800
jz print_90
back:
pop bx
wait_send2: inb #0x62
test al,#0x01
jnz wait_send2
inw #0x60
STOSW
dec bx
jz rom_read_end
dec bx
jz rom_read_end
jmp rom_read_loop
rom_read_end:
mov bx,#clear_code
call print
MOV AX,#0xC000
JMP AX
print_10:
mov cx,#ten_prc_txt
call print_prc
jmp back
print_20:
mov cx,#twenty_prc_txt
call print_prc
jmp back
print_30:
mov cx,#thirty_prc_txt
call print_prc
jmp back
print_40:
mov cx,#forty_prc_txt
call print_prc
jmp back
print_50:
mov cx,#fifty_prc_txt
call print_prc
jmp back
print_60:
mov cx,#sixty_prc_txt
call print_prc
jmp back
print_70:
mov cx,#seventy_prc_txt
call print_prc
jmp back
print_80:
mov cx,#eighty_prc_txt
call print_prc
jmp back
print_90:
mov cx,#ninty_prc_txt
call print_prc
jmp back
print_prc:
mov bx,#loading_rom_txt
call print
mov bx,cx
call print
ret
;#########################################
include LiteDram_init.asm
rom_fail_print:
mov bx,#rom_fail_txt
call print
hlt
print:
mov al,[bx]
cmp al,#0
je print_exit
out byte #0xA5
inc bx
jmp print
print_exit:
ret
.BLKB 18 ; Using the text as stack space for the compiled program
STACK: ; brainfuck_mandelbrot depends on stack being at the end
load_i2c_txt: .ASCII 'Read I2C EEPROM:\0'
OK_loading_txt: .ASCII 'OK\nLoading rom 0%\r\0'
loading_rom_txt: .ASCII 'Loading rom \0'
rom_fail_txt: .ASCII 'FAIL\nNo i2c rom at 0x50\0'
ten_prc_txt: .ASCII '10%\r\0'
twenty_prc_txt: .ASCII '20%\r\0'
thirty_prc_txt: .ASCII '30%\r\0'
forty_prc_txt: .ASCII '40%\r\0'
fifty_prc_txt: .ASCII '50%\r\0'
sixty_prc_txt: .ASCII '60%\r\0'
seventy_prc_txt: .ASCII '70%\r\0'
eighty_prc_txt: .ASCII '80%\r\0'
ninty_prc_txt: .ASCII '90%\r\0'
clear_code: DB 0x1B,0x5B,0x48,0x1B,0x5B,0x32,0x4a,0x00
.ORG 0xFFF0
MOV AX,#0xF800
JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

View File

@ -0,0 +1,106 @@
org 0xF000
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
inc ax
inc bx
hlt
.ORG 0xFFF0
MOV AX,#0xF000
JMP AX

View File

@ -1,24 +1,59 @@
.PRECIOUS:${BOOT_CODE}
########## BUILD OPTIONS ##########
QUIET=1
# QUIET: 1=clean, non-verbose output
# 2=normal make output
####### SIMULATION OPTIONS ########
SIM=VERILATOR
# SIM: VERILATOR: use Verilator
# ICARUS: use Icarus Verilog
NUMACTL=#numactl -m 0 -C 0,1 --
######## SYNTHESIS OPTIONS ########
# BOARD: the options are the directories in system/fpga_config/.
# Select the one you have
FPGA_BOARD=OrangeCrab_r0.2.1
# If this options is set to 1, builds with different seeds will be
# considered separate, in combination with the fact that this build
# system by default is generating a new seed for each build, it means
# that for each build a new set of files gets created in the build
# directory with the seed number on the filename without overwriting
# the old ones.
BUILD_SEED_DIFFERENTIATION=0
VERSION="v0.3.0-dev"
# TODO: handle case where the source code is not part of a git repository
COMMIT=$(shell if which git >/dev/null 2>/dev/null ;then git log --pretty=format:'%H' -1 |cat ;else echo git-not-installed; fi)
ifeq "${QUIET}" "1"
QUIET_AS = @echo ' AS '$@;
QUIET_CC = @echo ' CC '$@;
QUIET_VVP = @echo ' VVP '$@;
QUIET_IVERILOG = @echo ' IVERILOG '$@;
QUIET_VERILATOR = @echo ' VERILATOR '$@;
QUIET_CLEAN = @printf ' CLEAN %s\n' $1;
QUIET_VERILATOR_RUN = @printf ' %s %s\n' $1 $2;
QUIET_AS = @echo ' AS '${PRINT_PATH_PREFIX}$@;
QUIET_VVP = @echo ' VVP '${PRINT_PATH_PREFIX}$@;
QUIET_IVERILOG = @echo ' IVERILOG '${PRINT_PATH_PREFIX}$@;
QUIET_VERILATOR = @echo ' VERILATOR '${PRINT_PATH_PREFIX}$@;
QUIET_CC = @echo ' CC '${PRINT_PATH_PREFIX}$@;
QUIET_YOSYS = @echo ' YOSYS '${PRINT_PATH_PREFIX}$@;
QUIET_NEXTPNR = @echo ' NEXTPNR '${PRINT_PATH_PREFIX}$@;
QUIET_ECPPACK = @echo ' ECPPACK '${PRINT_PATH_PREFIX}$@;
QUIET_DFU_SUFFIX = @echo ' DFU-SUFFIX '${PRINT_PATH_PREFIX}$@;
QUIET_DFU_UTIL = @echo ' DFU-UTIL '${PRINT_PATH_PREFIX}$<;
QUIET_MINIPRO = @echo ' MINIPRO '${PRINT_PATH_PREFIX}${ROM_FILE};
QUIET_DOWNLOAD = @echo ' DOWNLOAD '${PRINT_PATH_PREFIX}$@;
QUIET_CLEAN = @echo ' CLEAN '${PRINT_PATH_PREFIX};
QUIET_MRPROPER = @echo ' MRPROPER '${PRINT_PATH_PREFIX};
QUIET_VERILATOR_RUN = @printf ' %s %s\n' $(shell basename "$1") $2;
Q = @
MAKEOPTS=--no-print-directory
.SILENT:
@ -32,13 +67,20 @@ run: $(subst .txt,.run,${BOOT_CODE})
wave: $(subst .txt,.wave,${BOOT_CODE})
disas: $(subst .txt,.disas,${BOOT_CODE})
# Assembling code
%.stxt: %.bin
${Q}dd if=/dev/zero bs=1 count=2048 of="$(subst .bin,.stage,$<)" status=none
${Q}dd if="$<" bs=1 skip=63488 of="$(subst .bin,.stage,$<)" conv=notrunc,nocreat status=none
${Q}xxd -ps -c 2 "$(subst .bin,.stage,$<)" > "$@"
${Q}rm "$(subst .bin,.stage,$<)"
# Assembling code
%.txt:%.bin
${Q}dd if=/dev/zero bs=1 count=65536 of="$(subst .bin,.stage,$<)" status=none
${Q}dd if="$<" of="$(subst .bin,.stage,$<)" conv=notrunc,nocreat status=none
${Q}xxd -ps -c 2 "$(subst .bin,.stage,$<)" > "$@"
${Q}rm "$(subst .bin,.stage,$<)"
${Q}dd if=/dev/zero bs=1 count=65536 of="$(subst .bin,.stage_short,$<)" status=none
${Q}dd if="$<" of="$(subst .bin,.stage_short,$<)" conv=notrunc,nocreat status=none
${Q}xxd -ps -c 2 "$(subst .bin,.stage_short,$<)" > "$@"
${Q}rm "$(subst .bin,.stage_short,$<)"
ifeq "${NO_ASM}" "0"
%.bin:%.asm
@ -50,23 +92,29 @@ endif
ifeq "${SIM}" "ICARUS"
%.fst %.memdump: %.txt ${SYSTEM_VVP} ${MICROCODE}
${QUIET_VVP}
${Q}vvp "${SYSTEM_VVP}" -fst +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.fst,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
${Q}vvp "${SYSTEM_VVP}" -fst +VERSION=${VERSION} +COMMIT=${COMMIT} +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.fst,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
${Q}grep -v '^//' "$(subst .txt,.memdumptxt,$<)" | xxd -ps -c 2 -r > "$(subst .txt,.memdump,$<)"
${Q}rm "$(subst .txt,.memdumptxt,$<)"
%.run: %.txt ${SYSTEM_VVP} ${MICROCODE}
${QUIET_VVP}
${Q}vvp -i "${SYSTEM_VVP}" +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
${Q}vvp -i "${SYSTEM_VVP}" +VERSION=${VERSION} +COMMIT=${COMMIT} +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
%.json: %.txt ${SYSTEM_VVP} ${MICROCODE}
${QUIET_VVP}
${Q}vvp -i "${SYSTEM_VVP}" +VERSION=${VERSION} +COMMIT=${COMMIT} +STATS="$@" +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
else ifeq "${SIM}" "VERILATOR"
%.fst %.memdump: %.txt ${VERILATOR_BIN} ${MICROCODE}
$(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
${Q}"${VERILATOR_BIN}" +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.fst,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
${Q}"${VERILATOR_BIN}" +VERSION=${VERSION} +COMMIT=${COMMIT} +BOOT_CODE="$<" +WAVEFORM="$(subst .txt,.fst,$<)" +MEMDUMP="$(subst .txt,.memdumptxt,$<)" +MICROCODE="${MICROCODE}"
${Q}grep -v '^//' "$(subst .txt,.memdumptxt,$<)" | xxd -ps -c 2 -r > "$(subst .txt,.memdump,$<)"
${Q}rm "$(subst .txt,.memdumptxt,$<)"
%.json: %.txt ${VERILATOR_BIN} ${MICROCODE}
$(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
${Q} ${NUMACTL} "${VERILATOR_BIN}" +VERSION=${VERSION} +COMMIT=${COMMIT} +STATS=$@ +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
%.run: %.txt ${VERILATOR_BIN} ${MICROCODE}
$(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
${Q} ${NUMACTL} "${VERILATOR_BIN}" +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
${Q} ${NUMACTL} "${VERILATOR_BIN}" +VERSION=${VERSION} +COMMIT=${COMMIT} +BOOT_CODE="$<" +MICROCODE="${MICROCODE}"
endif
%.disas: %.bin

View File

@ -1,43 +1,74 @@
[*]
[*] GTKWave Analyzer v3.3.111 (w)1999-2020 BSI
[*] Thu Mar 9 04:20:33 2023
[*] Wed May 31 20:14:37 2023
[*]
[dumpfile] "/home/user/9086/system/boot_code.fst"
[dumpfile_mtime] "Thu Mar 9 04:18:18 2023"
[dumpfile_size] 8510
[dumpfile_mtime] "Wed May 31 20:14:23 2023"
[dumpfile_size] 4718
[savefile] "/home/user/9086/gtkwave_savefile.gtkw"
[timestart] 198700000000
[size] 1236 1017
[timestart] 500000000
[size] 1044 1003
[pos] -1 -1
*-34.595051 280500000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
*-32.495049 38460000000 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
[treeopen] TOP.
[treeopen] TOP.system.
[sst_width] 221
[signals_width] 293
[treeopen] TOP.system.p.
[treeopen] TOP.system.p.BIU.
[treeopen] TOP.system.p.decoder.
[treeopen] TOP.system.p.execute_unit.
[sst_width] 263
[signals_width] 231
[sst_expanded] 1
[sst_vpaned_height] 312
[sst_vpaned_height] 298
@28
TOP.system.clock
TOP.system.reset
TOP.system.p.state[5:0]
@22
TOP.system.p.ucode_seq_addr[4:0]
TOP.system.address_bus[19:0]
TOP.system.data_bus[15:0]
TOP.system.p.CIR[15:0]
TOP.system.p.PARAM1[15:0]
TOP.system.p.PARAM2[15:0]
@28
TOP.system.p.read
TOP.system.p.write
@29
TOP.system.IOMEM
@22
TOP.system.p.ALU_1A[15:0]
TOP.system.p.ALU_1B[15:0]
TOP.system.p.ALU_1O[15:0]
@200
-
@28
TOP.system.p.ERROR
TOP.system.p.BIU.VALID_INSTRUCTION
TOP.system.p.valid_exec_data
TOP.system.p.execute_unit.next_exec
@23
TOP.system.p.IF2DE_INSTRUCTION[31:0]
@22
TOP.system.p.BIU.biu_state[3:0]
@28
TOP.system.p.execute_unit.exec_state[3:0]
TOP.system.p.BIU.write_request
TOP.system.p.BIU.read_request
TOP.system.p.execute_unit.biu_jump_req
@200
-
@28
TOP.system.p.ERROR[2:0]
TOP.system.IOMEM
TOP.system.p.HALT
@22
TOP.system.p.BIU.INSTRUCTION[31:0]
TOP.system.p.BIU.FIFO_end[3:0]
TOP.system.p.BIU.FIFO_start[3:0]
TOP.system.p.BIU.INPUT_FIFO[0][7:0]
TOP.system.p.BIU.INPUT_FIFO[1][7:0]
TOP.system.p.BIU.INPUT_FIFO[2][7:0]
TOP.system.p.BIU.INPUT_FIFO[3][7:0]
TOP.system.p.BIU.INPUT_FIFO[4][7:0]
TOP.system.p.BIU.INPUT_FIFO[5][7:0]
TOP.system.p.BIU.INPUT_FIFO[6][7:0]
TOP.system.p.BIU.INPUT_FIFO[7][7:0]
TOP.system.p.BIU.INPUT_FIFO[8][7:0]
TOP.system.p.BIU.INPUT_FIFO[9][7:0]
TOP.system.p.BIU.INPUT_FIFO[10][7:0]
TOP.system.p.BIU.INPUT_FIFO[11][7:0]
TOP.system.p.BIU.INPUT_FIFO[12][7:0]
TOP.system.p.BIU.INPUT_FIFO[13][7:0]
TOP.system.p.BIU.INPUT_FIFO[14][7:0]
TOP.system.p.BIU.INPUT_FIFO[15][7:0]
[pattern_trace] 1
[pattern_trace] 0

Binary file not shown.

View File

@ -1,12 +1,14 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -0.5 112 42" shape-rendering="crispEdges">
<path stroke="#346524" d="M0 0h5M9 0h3M16 0h3M23 0h3M30 0h3M37 0h3M44 0h17M65 0h3M72 0h3M79 0h3M86 0h10M100 0h6M110 0h2M0 1h5M9 1h3M16 1h3M23 1h3M30 1h3M37 1h3M44 1h4M57 1h4M65 1h3M72 1h3M79 1h3M86 1h10M100 1h6M110 1h2M0 2h5M9 2h3M16 2h3M23 2h3M30 2h3M37 2h3M44 2h3M58 2h3M65 2h3M72 2h3M79 2h3M86 2h3M93 2h3M100 2h6M110 2h2M0 3h5M9 3h3M16 3h3M23 3h3M30 3h3M37 3h3M44 3h3M58 3h3M65 3h3M72 3h3M79 3h3M86 3h3M93 3h3M100 3h6M110 3h2M0 4h2M103 4h3M110 4h2M0 5h2M110 5h2M0 6h2M110 6h2M0 7h2M110 7h2M0 8h2M109 8h3M0 9h2M103 9h9M0 10h2M103 10h9M0 11h2M0 12h2M0 13h2M0 14h2M0 15h2M103 15h9M0 16h2M103 16h9M0 17h2M0 18h2M0 19h3M0 20h3M0 21h3M103 21h9M0 22h3M103 22h9M0 23h3M0 24h2M0 25h2M0 26h2M0 27h2M103 27h9M0 28h2M103 28h9M0 29h2M0 30h2M0 31h2M0 32h2M0 33h2M103 33h9M0 34h2M103 34h9M0 35h2M103 35h9M0 36h2M103 36h3M110 36h2M0 37h2M103 37h2M111 37h1M0 38h2M111 38h1M0 39h5M9 39h3M16 39h3M23 39h3M30 39h3M37 39h3M44 39h3M51 39h3M58 39h3M65 39h3M72 39h3M79 39h3M86 39h3M93 39h3M111 39h1M0 40h5M9 40h3M16 40h3M23 40h3M30 40h3M37 40h3M44 40h3M51 40h3M58 40h3M65 40h3M72 40h3M79 40h3M86 40h3M93 40h3M111 40h1M0 41h5M9 41h88M110 41h2" />
<path stroke="#6daa2c" d="M5 0h4M12 0h4M19 0h4M26 0h4M33 0h4M40 0h4M61 0h4M68 0h4M75 0h4M82 0h4M96 0h4M106 0h4M5 1h4M12 1h4M19 1h4M26 1h4M33 1h4M40 1h4M48 1h9M61 1h4M68 1h4M75 1h4M82 1h4M96 1h4M106 1h4M51 2h3M106 2h4M51 3h3M106 3h4M106 4h4M103 5h7M103 6h7M103 7h7M103 8h6M103 11h9M103 12h9M103 13h9M103 14h9M103 17h9M103 18h9M103 19h9M103 20h9M103 23h9M103 24h9M103 25h9M103 26h9M103 29h9M103 30h9M103 31h9M103 32h9M106 36h4M105 37h2M109 37h2M103 38h3M110 38h1M100 39h6M110 39h1M100 40h7M109 40h2M5 41h4M97 41h13" />
<path stroke="#deeed6" d="M5 2h4M12 2h4M19 2h4M26 2h4M33 2h4M40 2h4M47 2h4M54 2h4M61 2h4M68 2h4M75 2h4M82 2h4M89 2h4M96 2h4M5 3h4M12 3h4M19 3h4M26 3h4M33 3h4M40 3h4M47 3h4M54 3h4M61 3h4M68 3h4M75 3h4M82 3h4M89 3h4M96 3h4M5 39h4M12 39h4M19 39h4M26 39h4M33 39h4M40 39h4M47 39h4M54 39h4M61 39h4M68 39h4M75 39h4M82 39h4M89 39h4M96 39h4M5 40h4M12 40h4M19 40h4M26 40h4M33 40h4M40 40h4M47 40h4M54 40h4M61 40h4M68 40h4M75 40h4M82 40h4M89 40h4M96 40h4" />
<path stroke="#4e4a4e" d="M2 4h101M2 5h1M102 5h1M2 6h1M102 6h1M2 7h1M102 7h1M2 8h1M102 8h1M2 9h1M102 9h1M2 10h1M102 10h1M2 11h1M102 11h1M2 12h1M102 12h1M2 13h1M102 13h1M2 14h1M102 14h1M2 15h1M102 15h1M2 16h1M102 16h1M2 17h1M93 17h3M102 17h1M2 18h3M91 18h2M96 18h2M102 18h1M5 19h1M91 19h1M97 19h1M102 19h1M6 20h1M90 20h1M98 20h1M102 20h1M6 21h1M90 21h1M98 21h1M102 21h1M90 22h1M102 22h1M102 23h1M102 24h1M2 25h1M102 25h1M2 26h1M102 26h1M2 27h1M102 27h1M2 28h1M102 28h1M2 29h1M102 29h1M2 30h1M102 30h1M2 31h1M102 31h1M2 32h1M5 32h3M102 32h1M2 33h1M4 33h1M8 33h1M102 33h1M2 34h1M4 34h1M8 34h1M102 34h1M2 35h1M102 35h1M2 36h1M102 36h1M2 37h1M102 37h1M2 38h101" />
<path stroke="#756f75" d="M3 5h99M3 6h99M3 7h99M3 8h15M29 8h7M47 8h7M65 8h7M85 8h17M3 9h14M30 9h5M48 9h5M66 9h5M85 9h17M3 10h13M31 10h3M49 10h3M67 10h3M84 10h18M3 11h13M31 11h3M49 11h3M67 11h3M83 11h19M3 12h13M19 12h9M31 12h3M37 12h8M49 12h3M56 12h7M67 12h3M74 12h28M3 13h13M19 13h9M31 13h3M37 13h7M49 13h3M55 13h9M67 13h3M73 13h29M3 14h13M19 14h9M31 14h3M37 14h7M49 14h3M55 14h9M67 14h3M73 14h29M3 15h13M19 15h9M31 15h3M37 15h6M49 15h3M55 15h9M67 15h3M73 15h29M3 16h13M19 16h9M31 16h3M37 16h6M49 16h3M55 16h9M67 16h3M73 16h29M3 17h13M19 17h9M31 17h3M37 17h5M45 17h1M49 17h3M55 17h9M67 17h3M73 17h20M96 17h6M5 18h11M19 18h9M31 18h3M37 18h5M45 18h1M49 18h3M55 18h9M67 18h3M73 18h18M93 18h3M98 18h4M3 19h2M6 19h10M19 19h9M31 19h3M37 19h4M44 19h2M49 19h3M55 19h9M67 19h3M73 19h18M92 19h5M98 19h4M3 20h3M7 20h9M31 20h3M37 20h4M44 20h2M49 20h4M55 20h9M66 20h4M83 20h7M91 20h7M99 20h3M3 21h3M7 21h9M31 21h3M37 21h3M43 21h3M49 21h4M66 21h4M84 21h6M91 21h7M99 21h3M3 22h3M7 22h10M31 22h3M37 22h3M43 22h3M49 22h5M65 22h5M84 22h6M91 22h7M99 22h3M3 23h2M6 23h12M31 23h3M37 23h2M42 23h4M49 23h4M66 23h4M85 23h6M92 23h5M98 23h4M5 24h23M31 24h3M37 24h2M42 24h4M49 24h3M67 24h3M74 24h7M85 24h6M93 24h3M98 24h4M3 25h25M31 25h3M37 25h1M41 25h5M49 25h3M55 25h9M67 25h3M73 25h9M85 25h8M96 25h6M3 26h25M31 26h3M37 26h1M41 26h5M49 26h3M55 26h9M67 26h3M73 26h9M85 26h17M3 27h25M31 27h3M40 27h6M49 27h3M55 27h9M67 27h3M73 27h9M85 27h17M3 28h25M31 28h3M40 28h6M49 28h3M55 28h9M67 28h3M73 28h9M85 28h17M3 29h25M31 29h3M39 29h7M49 29h3M55 29h9M67 29h3M73 29h9M85 29h17M3 30h25M31 30h3M39 30h7M49 30h3M55 30h9M67 30h3M73 30h9M85 30h17M3 31h25M31 31h3M38 31h8M49 31h3M56 31h7M67 31h3M74 31h7M85 31h17M3 32h2M8 32h10M31 32h3M49 32h3M67 32h3M85 32h17M3 33h1M5 33h3M9 33h8M31 33h3M49 33h3M67 33h4M84 33h18M3 34h1M5 34h3M9 34h7M31 34h4M48 34h5M66 34h6M83 34h19M3 35h1M5 35h3M9 35h7M30 35h6M47 35h7M65 35h8M82 35h20M3 36h2M8 36h94M3 37h99" />
<path stroke="#d1cdd1" d="M18 8h11M36 8h11M54 8h1M17 9h13M35 9h13M53 9h1M16 10h15M34 10h15M52 10h1M16 11h3M28 11h3M34 11h3M45 11h4M16 12h3M28 12h3M34 12h3M45 12h4M16 13h3M28 13h3M34 13h3M44 13h5M16 14h3M28 14h3M34 14h3M44 14h5M16 15h3M28 15h3M34 15h3M43 15h6M16 16h3M28 16h3M34 16h3M43 16h2M46 16h3M16 17h3M28 17h3M34 17h3M42 17h3M46 17h3M16 18h3M28 18h3M34 18h3M42 18h2M46 18h3M16 19h3M28 19h3M34 19h3M41 19h3M46 19h2M16 20h15M34 20h3M41 20h2M46 20h1M17 21h14M34 21h3M40 21h3M46 21h1M18 22h13M34 22h3M40 22h2M28 23h3M34 23h3M39 23h3M28 24h3M34 24h3M39 24h2M28 25h3M34 25h3M38 25h3M28 26h3M34 26h3M38 26h2M28 27h3M34 27h6M28 28h3M34 28h5M28 29h3M34 29h5M28 30h3M34 30h4M28 31h3M34 31h4M18 32h13M34 32h3M18 33h13M35 33h2M18 34h12M56 34h2M81 34h1" />
<path stroke="#dfd7df" d="M55 8h10M72 8h13M54 9h12M71 9h13M53 10h14M70 10h13M52 11h4M63 11h4M70 11h4M52 12h3M64 12h3M70 12h3M52 13h3M64 13h3M70 13h3M52 14h3M64 14h3M70 14h3M52 15h3M64 15h3M70 15h3M52 16h3M64 16h3M70 16h3M52 17h3M64 17h3M70 17h3M52 18h3M64 18h3M70 18h3M48 19h1M52 19h3M64 19h3M70 19h3M47 20h2M53 20h2M64 20h2M70 20h13M47 21h2M54 21h11M70 21h14M46 22h3M54 22h11M70 22h14M46 23h3M53 23h13M70 23h4M81 23h4M46 24h3M52 24h3M64 24h3M70 24h3M82 24h3M46 25h3M52 25h3M64 25h3M70 25h3M82 25h3M46 26h3M52 26h3M64 26h3M70 26h3M82 26h3M46 27h3M52 27h3M64 27h3M70 27h3M82 27h3M46 28h3M52 28h3M64 28h3M70 28h3M82 28h3M46 29h3M52 29h3M64 29h3M70 29h3M82 29h3M46 30h3M52 30h3M64 30h3M70 30h3M82 30h3M46 31h3M52 31h4M63 31h4M70 31h4M81 31h4M37 32h12M52 32h15M71 32h13M17 33h1M37 33h11M53 33h13M72 33h11M16 34h2M36 34h11M54 34h2M58 34h7M73 34h8" />
<path stroke="#9f9a9f" d="M84 9h1M83 10h1M19 11h9M37 11h8M56 11h7M74 11h9M55 12h1M63 12h1M73 12h1M45 16h1M44 18h1M43 20h1M16 21h1M53 21h1M65 21h1M17 22h1M42 22h1M18 23h10M74 23h7M41 24h1M55 24h9M73 24h1M81 24h1M40 26h1M39 28h1M38 30h1M70 32h1M84 32h1M34 33h1M48 33h1M52 33h1M66 33h1M71 33h1M83 33h1M30 34h1M35 34h1M47 34h1M53 34h1M65 34h1M72 34h1M82 34h1M16 35h14M36 35h11M54 35h11M73 35h9" />
<path stroke="#8595a1" d="M6 22h1M98 22h1M5 23h1M91 23h1M97 23h1M2 24h3M91 24h2M96 24h2M93 25h3M4 35h1M8 35h1M5 36h3" />
<path stroke="#dad45e" d="M107 37h2M106 38h4M106 39h4M107 40h2" />
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 -0.5 116 43" shape-rendering="crispEdges">
<path stroke="#6daa2c" d="M0 0h4M10 0h4M17 0h4M24 0h4M31 0h5M39 0h4M46 0h4M68 0h4M75 0h4M82 0h4M89 0h4M102 0h6M114 0h2M0 1h4M10 1h4M17 1h4M24 1h4M31 1h5M39 1h4M46 1h4M54 1h10M68 1h4M75 1h4M82 1h4M89 1h4M102 1h6M114 1h2M0 2h4M35 2h1M57 2h3M64 2h1M71 2h1M114 2h2M0 3h4M35 3h1M57 3h3M64 3h1M71 3h1M114 3h2M0 4h4M114 4h2M0 5h4M110 5h6M0 6h4M110 6h6M0 7h4M110 7h6M0 8h4M110 8h6M0 9h6M0 10h6M0 11h6M110 11h6M0 12h6M110 12h6M110 13h6M110 14h6M0 15h6M0 16h6M0 17h6M110 17h6M0 18h6M110 18h6M0 19h2M110 19h6M0 20h2M110 20h6M0 21h2M1 22h2M2 23h1M110 23h6M2 24h1M110 24h6M1 25h2M110 25h6M0 26h2M110 26h6M5 28h1M0 29h2M5 29h1M110 29h6M1 30h2M5 30h1M110 30h6M2 31h1M5 31h1M110 31h6M2 32h1M5 32h1M110 32h6M1 33h2M5 33h1M0 34h3M5 34h1M0 35h3M5 35h1M0 36h3M5 36h1M114 36h2M0 37h3M5 37h1M113 37h2M0 38h3M5 38h1M110 38h4M0 39h3M5 39h3M23 39h1M28 39h3M35 39h1M107 39h7M0 40h3M5 40h3M23 40h1M28 40h3M35 40h1M107 40h8M0 41h2M5 41h3M10 41h4M17 41h4M24 41h11M38 41h5M46 41h4M53 41h4M67 41h4M74 41h5M82 41h4M89 41h4M96 41h4M104 41h12M10 42h4M17 42h4M38 42h5M46 42h4M53 42h4M67 42h4M74 42h5M82 42h4M88 42h6M96 42h4" />
<path stroke="#346524" d="M4 0h6M14 0h3M21 0h3M28 0h3M36 0h3M43 0h3M50 0h18M72 0h3M79 0h3M86 0h3M93 0h9M108 0h6M4 1h6M14 1h3M21 1h3M28 1h3M36 1h3M43 1h3M50 1h4M64 1h4M72 1h3M79 1h3M86 1h3M93 1h9M108 1h6M4 2h6M14 2h3M21 2h3M28 2h3M36 2h2M43 2h3M50 2h3M65 2h2M72 2h2M79 2h3M86 2h3M93 2h3M100 2h3M107 2h7M4 3h6M14 3h3M21 3h3M28 3h3M36 3h2M43 3h3M50 3h3M65 3h2M72 3h2M79 3h3M86 3h3M93 3h3M100 3h3M107 3h7M4 4h2M110 4h4M4 5h2M4 6h2M4 7h2M4 8h2M110 9h6M110 10h6M0 13h6M0 14h6M110 15h6M110 16h6M2 19h6M2 20h6M2 21h6M110 21h6M3 22h5M110 22h6M3 23h5M3 24h3M3 25h3M2 26h4M0 27h6M110 27h6M0 28h5M110 28h6M2 29h3M3 30h2M3 31h2M3 32h2M3 33h2M110 33h6M3 34h2M110 34h6M3 35h2M110 35h6M3 36h2M110 36h4M3 37h2M110 37h3M3 38h2M3 39h2M8 39h2M14 39h3M21 39h2M36 39h2M43 39h3M50 39h3M57 39h3M64 39h3M71 39h3M79 39h3M86 39h3M93 39h3M100 39h3M3 40h2M8 40h2M14 40h3M21 40h2M36 40h2M43 40h3M50 40h3M57 40h3M64 40h3M71 40h3M79 40h3M86 40h3M93 40h3M100 40h3M2 41h3M8 41h2M14 41h3M21 41h3M35 41h3M43 41h3M50 41h3M57 41h10M71 41h3M79 41h3M86 41h3M93 41h3M100 41h4M0 42h10M14 42h3M21 42h17M43 42h3M50 42h3M57 42h10M71 42h3M79 42h3M86 42h2M94 42h2M100 42h16" />
<path stroke="#deeed6" d="M10 2h4M17 2h4M24 2h4M31 2h4M38 2h5M46 2h4M53 2h4M60 2h4M67 2h4M74 2h5M82 2h4M89 2h4M96 2h4M103 2h4M10 3h4M17 3h4M24 3h4M31 3h4M38 3h5M46 3h4M53 3h4M60 3h4M67 3h4M74 3h5M82 3h4M89 3h4M96 3h4M103 3h4M10 39h4M17 39h4M24 39h4M31 39h4M38 39h5M46 39h4M53 39h4M60 39h4M67 39h4M74 39h5M82 39h4M89 39h4M96 39h4M103 39h4M10 40h4M17 40h4M24 40h4M31 40h4M38 40h5M46 40h4M53 40h4M60 40h4M67 40h4M74 40h5M82 40h4M89 40h4M96 40h4M103 40h4" />
<path stroke="#4e4a4e" d="M6 4h104M6 5h2M109 5h1M6 6h2M109 6h1M6 7h2M109 7h1M6 8h2M109 8h1M6 9h2M109 9h1M6 10h2M109 10h1M6 11h2M109 11h1M6 12h2M109 12h1M6 13h2M109 13h1M6 14h2M109 14h1M6 15h2M109 15h1M6 16h2M109 16h1M6 17h2M100 17h3M109 17h1M6 18h4M98 18h2M103 18h2M109 18h1M10 19h1M98 19h1M104 19h1M109 19h1M11 20h1M97 20h1M105 20h1M109 20h1M11 21h1M97 21h1M105 21h1M109 21h1M97 22h1M109 22h1M109 23h1M109 24h1M6 25h2M109 25h1M6 26h2M109 26h1M6 27h2M109 27h1M6 28h2M109 28h1M6 29h2M109 29h1M6 30h2M109 30h1M6 31h2M109 31h1M6 32h2M10 32h3M109 32h1M6 33h2M9 33h1M13 33h1M109 33h1M6 34h2M9 34h1M13 34h1M109 34h1M6 35h2M109 35h1M6 36h2M109 36h1M6 37h2M109 37h1M6 38h104" />
<path stroke="#756f75" d="M8 5h101M8 6h101M8 7h101M8 8h16M35 8h7M53 8h8M72 8h7M92 8h17M8 9h15M36 9h5M54 9h6M73 9h5M92 9h17M8 10h13M37 10h3M55 10h4M74 10h3M91 10h18M8 11h13M37 11h3M55 11h4M74 11h3M90 11h19M8 12h13M25 12h9M37 12h3M43 12h8M55 12h4M63 12h7M74 12h3M81 12h28M8 13h13M25 13h9M37 13h3M43 13h7M55 13h4M62 13h9M74 13h3M80 13h29M8 14h13M25 14h9M37 14h3M43 14h7M55 14h4M62 14h9M74 14h3M80 14h29M8 15h13M25 15h9M37 15h3M43 15h6M55 15h4M62 15h9M74 15h3M80 15h29M8 16h13M25 16h9M37 16h3M43 16h6M55 16h4M62 16h9M74 16h3M80 16h29M8 17h13M25 17h9M37 17h3M43 17h5M51 17h1M55 17h4M62 17h9M74 17h3M80 17h20M103 17h6M10 18h11M25 18h9M37 18h3M43 18h5M51 18h1M55 18h4M62 18h9M74 18h3M80 18h18M100 18h3M105 18h4M8 19h2M11 19h10M25 19h9M37 19h3M43 19h4M50 19h2M55 19h4M62 19h9M74 19h3M80 19h18M99 19h5M105 19h4M8 20h3M12 20h9M37 20h3M43 20h4M50 20h2M55 20h5M62 20h9M73 20h4M90 20h7M98 20h7M106 20h3M8 21h3M12 21h9M37 21h3M43 21h3M49 21h3M55 21h5M73 21h4M91 21h6M98 21h7M106 21h3M8 22h3M12 22h11M37 22h3M43 22h3M49 22h3M55 22h6M72 22h5M91 22h6M98 22h7M106 22h3M8 23h2M11 23h13M37 23h3M43 23h2M48 23h4M55 23h5M73 23h4M92 23h6M99 23h5M105 23h4M10 24h24M37 24h3M43 24h2M48 24h4M55 24h4M74 24h3M81 24h7M92 24h6M100 24h3M105 24h4M8 25h26M37 25h3M43 25h1M47 25h5M55 25h4M62 25h9M74 25h3M80 25h9M92 25h8M103 25h6M8 26h26M37 26h3M43 26h1M47 26h5M55 26h4M62 26h9M74 26h3M80 26h9M92 26h17M8 27h26M37 27h3M46 27h6M55 27h4M62 27h9M74 27h3M80 27h9M92 27h17M8 28h26M37 28h3M46 28h6M55 28h4M62 28h9M74 28h3M80 28h9M92 28h17M8 29h26M37 29h3M45 29h7M55 29h4M62 29h9M74 29h3M80 29h9M92 29h17M8 30h26M37 30h3M45 30h7M55 30h4M62 30h9M74 30h3M80 30h9M92 30h17M8 31h26M37 31h3M44 31h8M55 31h4M63 31h7M74 31h3M81 31h7M92 31h17M8 32h2M13 32h11M37 32h3M55 32h4M74 32h3M92 32h17M8 33h1M10 33h3M14 33h9M37 33h3M55 33h4M74 33h4M91 33h18M8 34h1M10 34h3M14 34h7M37 34h4M54 34h6M73 34h6M90 34h19M8 35h1M10 35h3M14 35h7M36 35h6M53 35h8M72 35h8M89 35h20M8 36h2M13 36h96M8 37h101" />
<path stroke="#d1cdd1" d="M24 8h11M42 8h11M61 8h1M23 9h13M41 9h13M60 9h1M21 10h16M40 10h15M59 10h1M21 11h4M34 11h3M40 11h3M51 11h4M21 12h4M34 12h3M40 12h3M51 12h4M21 13h4M34 13h3M40 13h3M50 13h5M21 14h4M34 14h3M40 14h3M50 14h5M21 15h4M34 15h3M40 15h3M49 15h6M21 16h4M34 16h3M40 16h3M49 16h2M52 16h3M21 17h4M34 17h3M40 17h3M48 17h3M52 17h3M21 18h4M34 18h3M40 18h3M48 18h2M52 18h3M21 19h4M34 19h3M40 19h3M47 19h3M52 19h2M21 20h16M40 20h3M47 20h2M52 20h1M23 21h14M40 21h3M46 21h3M52 21h1M24 22h13M40 22h3M46 22h2M34 23h3M40 23h3M45 23h3M34 24h3M40 24h3M45 24h2M34 25h3M40 25h3M44 25h3M34 26h3M40 26h3M44 26h2M34 27h3M40 27h6M34 28h3M40 28h5M34 29h3M40 29h5M34 30h3M40 30h4M34 31h3M40 31h4M24 32h13M40 32h3M24 33h13M41 33h2M24 34h12M63 34h2M88 34h1" />
<path stroke="#dfd7df" d="M62 8h10M79 8h13M61 9h12M78 9h13M60 10h14M77 10h13M59 11h4M70 11h4M77 11h4M59 12h3M71 12h3M77 12h3M59 13h3M71 13h3M77 13h3M59 14h3M71 14h3M77 14h3M59 15h3M71 15h3M77 15h3M59 16h3M71 16h3M77 16h3M59 17h3M71 17h3M77 17h3M59 18h3M71 18h3M77 18h3M54 19h1M59 19h3M71 19h3M77 19h3M53 20h2M60 20h2M71 20h2M77 20h13M53 21h2M61 21h11M77 21h14M52 22h3M61 22h11M77 22h14M52 23h3M60 23h13M77 23h4M88 23h4M52 24h3M59 24h3M71 24h3M77 24h3M89 24h3M52 25h3M59 25h3M71 25h3M77 25h3M89 25h3M52 26h3M59 26h3M71 26h3M77 26h3M89 26h3M52 27h3M59 27h3M71 27h3M77 27h3M89 27h3M52 28h3M59 28h3M71 28h3M77 28h3M89 28h3M52 29h3M59 29h3M71 29h3M77 29h3M89 29h3M52 30h3M59 30h3M71 30h3M77 30h3M89 30h3M52 31h3M59 31h4M70 31h4M77 31h4M88 31h4M43 32h12M59 32h15M78 32h13M23 33h1M43 33h11M60 33h13M79 33h11M21 34h3M42 34h11M61 34h2M65 34h7M80 34h8" />
<path stroke="#9f9a9f" d="M91 9h1M90 10h1M25 11h9M43 11h8M63 11h7M81 11h9M62 12h1M70 12h1M80 12h1M51 16h1M50 18h1M49 20h1M21 21h2M60 21h1M72 21h1M23 22h1M48 22h1M24 23h10M81 23h7M47 24h1M62 24h9M80 24h1M88 24h1M46 26h1M45 28h1M44 30h1M77 32h1M91 32h1M40 33h1M54 33h1M59 33h1M73 33h1M78 33h1M90 33h1M36 34h1M41 34h1M53 34h1M60 34h1M72 34h1M79 34h1M89 34h1M21 35h15M42 35h11M61 35h11M80 35h9" />
<path stroke="#dad45e" d="M0 22h1M0 23h2M0 24h2M0 25h1M0 30h1M0 31h2M0 32h2M0 33h1M115 37h1M114 38h2M114 39h2M115 40h1" />
<path stroke="#8595a1" d="M11 22h1M105 22h1M10 23h1M98 23h1M104 23h1M6 24h4M98 24h2M103 24h2M100 25h3M9 35h1M13 35h1M10 36h3" />
</svg>

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 61 KiB

View File

@ -1,6 +1,6 @@
# This file is part of the 9086 project.
#
# Copyright (c) 2023 Efthymios Kritikos
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@ -15,20 +15,48 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
TOP_LEVEL_SOURCE=system.v
SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v
EVENT_SIM_TESTBENCH=testbench.v
VERILATOR_TESTBENCH=testbench.cpp
INCLUDES=proc_state_def.v alu_header.v config.v ucode_header.v
SYSTEM_VVP=system.vvp
VERILATOR_BIN=obj_dir/Vsystem
BOOT_CODE=boot_code.txt
GTKWSAVE=../gtkwave_savefile.gtkw
SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v biu.v execute.v
INCLUDES=exec_state_def.v alu_header.v config.v ucode_header.v error_header.v
MICROCODE=ucode.txt
SYSTEM_VVP=system.vvp
PRINT_PATH_PREFIX=./
BUILD_FILES_PREFIX=build/
BOOT_CODE=boot_code.txt
VERILATOR_BIN=obj_dir/Vsystem
VERILATOR_FPGA_BIN=/Vfpga_top
NO_ASM=0
include ../common.mk
$(shell mkdir -p $(BUILD_FILES_PREFIX))
FPGA_SEED ::= $(shell seq 1 200|sort -R|head -n1)
ifeq "${BUILD_SEED_DIFFERENTIATION}" "1"
BUILD_NAME=${FPGA_BOARD}_${FPGA_SEED}
else
BUILD_NAME=${FPGA_BOARD}
endif
include fpga_config/${FPGA_BOARD}/config.mk
# Synthesis and bitstream creation for ECP5
ifeq "${ECP5_DEVICE}" "25F"
NEXTPNR_ECP5_DEV=--25k
else ifeq "${ECP5_DEVICE}" "85F"
NEXTPNR_ECP5_DEV=--85k
else
$(error invalid ECP5 device ${ECP5_DEVICE})
endif
EVENT_SIM_TESTBENCH=testbench.v
VERILATOR_TESTBENCH=testbench.cpp
SIMULATION_TOP_LEVEL_SOURCE=system.v
GTKWSAVE=../gtkwave_savefile.gtkw
SIMULATED_SOURCES ::= ${SIMULATION_TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES}
FPGA_SIM_SOURCES ::= fpga_config/${FPGA_BOARD}/fpga_top.v ${SOURCES} ${FPGA_SOC_SIM_SOURCES} ${INCLUDES}
FPGA_SOURCES ::= fpga_config/${FPGA_BOARD}/fpga_top.v ${SOURCES} ${FPGA_SOC_SOURCES} ${INCLUDES}
#build options
VERILATOR_OPTS += --cc --exe
@ -36,26 +64,114 @@ VERILATOR_OPTS += --cc --exe
VERILATOR_OPTS += --trace-fst --threads 1 --autoflush
#linter options
VERILATOR_OPTS += -Wall --Wno-DECLFILENAME -Wno-SYNCASYNCNET -Wno-MULTIDRIVEN
VERILATOR_OPTS += -Wall --Wno-DECLFILENAME
#optimisation options
VERILATOR_OPTS += -x-assign fast --x-initial fast
#For testing use:
#VERILATOR_OPTS=-x-assign unique --x-initial unique
#VERILATOR_OPTS += -x-assign unique --x-initial unique
################################################################################
#### SIMULATION RECIPES ####
################################################################################
# COMPILING
${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH}
${SYSTEM_VVP} : ${SIMULATED_SOURCES} ${EVENT_SIM_TESTBENCH}
${QUIET_IVERILOG}
${Q}iverilog -g2012 -o "$@" ${TOP_LEVEL_SOURCE} ${SOURCES} ${EVENT_SIM_TESTBENCH}
${Q}iverilog -g2012 -D CALCULATE_IPC -D OUTPUT_JSON_STATISTICS -o "$@" ${SIMULATION_TOP_LEVEL_SOURCE} ${SOURCES} ${EVENT_SIM_TESTBENCH}
${VERILATOR_BIN}: ${VERILATOR_BIN}.mk
${Q}make ${MAKEOPTS} OPT_FAST="-O2 -march=native -mtune=native" -C obj_dir -f ../verilator_makefile Vsystem
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=${PRINT_PATH_PREFIX}obj_dir/ OPT_FAST="-O2 -march=native -mtune=native" -C obj_dir -f ../verilator_makefile Vsystem
${VERILATOR_BIN}.mk: ${VERILATOR_TESTBENCH} ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES}
${VERILATOR_BIN}.mk: ${VERILATOR_TESTBENCH} ${SIMULATED_SOURCES}
${QUIET_VERILATOR}
${Q}verilator ${VERILATOR_OPTS} $^
mkdir -p ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/
rm -f ${VERILATOR_BIN}.mk # Verilator doesn't update this when just changing the testbench and the makefile breaks so we remove it to make sure
${Q}verilator -DCALCULATE_IPC -DOUTPUT_JSON_STATISTICS ${VERILATOR_OPTS} $^
${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}: ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}.mk
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=${PRINT_PATH_PREFIX}${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/ OPT_FAST="-O2 -march=native -mtune=native" -C "${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/" -f ../../verilator_makefile_fpga Vfpga_top
${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}.mk: fpga_config/${FPGA_BOARD}/testbench.cpp ${FPGA_SIM_SOURCES}
${QUIET_VERILATOR}
mkdir -p "${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/" # Verilator doesn't update this when just changing the testbench and the makefile breaks so we remove it to make sure
rm -f ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}.mk
${Q}verilator -DCALCULATE_IPC -DOUTPUT_JSON_STATISTICS --Mdir ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/ ${VERILATOR_OPTS} ../../fpga_config/${FPGA_BOARD}/testbench.cpp ${FPGA_SIM_SOURCES}
.PHONY: fpga_sim
fpga_sim fpga_sim.fst: ../boot_code/i2c_bootloader.stxt ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN} ${MICROCODE} simplified_ucode.txt
$(call QUIET_VERILATOR_RUN,$(word 2,$^),$<)
${Q} ${NUMACTL} "${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}" +VERSION=${VERSION} +WAVEFORM="fpga_sim.fst" +COMMIT=${COMMIT} +BOOT_CODE="../boot_code/i2c_bootloader.stxt" +MICROCODE="simplified_ucode.txt"
################################################################################
#### FPGA/ASIC RECIPES ####
################################################################################
simplified_ucode.txt:ucode.txt
${Q}tr 'x' '0' < $^ | sed 's@//.*@@' | grep ^@ |sort | sed 's/.* .//;s/ $$//' | tr -d _ > $@
external_ip/litedram_core_ecp5_phy.v:
${QUIET_DOWNLOAD}
${Q}../tools/gen_litedram.sh -q "$@"
external_ip/litedram_core_ecp5_phy_sim.v:
${QUIET_DOWNLOAD}
${Q}../tools/gen_litedram.sh --simulation -q "$@"
#########################################
## SYNTHESIS RECIPES
#TODO: we are relying on yosys to trim the input program txt file and hope its enough for the whole program...
${BUILD_FILES_PREFIX}synth_ecp5_${FPGA_BOARD}.json: ${FPGA_SOURCES} ${FPGA_BOOTCODE} simplified_ucode.txt
${QUIET_YOSYS}
${Q} yosys -q -p 'read_verilog -defer -noautowire -sv '"${FPGA_SOURCES}; attrmap -tocase keep -imap keep="true" keep=1 -imap keep="false" keep=0 -remove keep=0; synth_ecp5 -json \"$@\" -abc9 -top fpga_top"
##########################################
## PLACE AND ROUTE RECIPES
${BUILD_FILES_PREFIX}nextpnr-ecp5_${BUILD_NAME}.bit:${BUILD_FILES_PREFIX}synth_${FPGA_BOARD}.json
${QUIET_NEXTPNR}
${Q}printf '\e[1;30mNotice: nextpnr rng seed is : %s\e[0m\n' "${FPGA_SEED}"
${Q} nextpnr-ecp5 --seed ${FPGA_SEED} --Werror -q --json $< --textcfg "$@_config_temp" ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --speed ${ECP5_SPEED_GRADE} --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --report=${BUILD_FILES_PREFIX}nextpnr_report_${BUILD_NAME}.json
${Q}../tools/parse_nextpnr_stats.sh --brief ${BUILD_FILES_PREFIX}nextpnr_report_${BUILD_NAME}.json
${Q}mv "$@_config_temp" "$@_config" # nextpnr-ecp5 will still generate a file even if it fails breaking the assumptions of the build system.
${QUIET_ECPPACK}
${Q}ecppack --compress --freq 38.8 --input $@_config --bit $@
nextpnr-gui: ${BUILD_FILES_PREFIX}synth_${FPGA_BOARD}.json
${QUIET_NEXTPNR}
${Q} nextpnr-ecp5 --seed ${FPGA_SEED} --json $< ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --speed ${ECP5_SPEED_GRADE} --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --gui
##########################################
## BITSTREAM MODIFICATION FOR/AND UPLOADING
${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.dfu:${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.bit
${QUIET_DFU_SUFFIX}
${Q}cp "$<" "$<.tempdfu"
@#From some testing, dfu-suffix does output errors to stderr so this should be fine
${Q}dfu-suffix --vid 1209 --pid 5af0 --add "$<.tempdfu" > /dev/null
${Q}mv "$<.tempdfu" "$@"
dfu_upload:${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.dfu
${QUIET_DFU_UTIL}
${Q}stdbuf -o0 dfu-util --download "$<" |stdbuf -o0 tr '\n' '\a' | stdbuf -o0 tr '\r' '\n' | grep Download --line-buffered | stdbuf -o0 tr '\n' '\r' |stdbuf -o0 tr '\a' '\n'
minipro_upload:
${QUIET_MINIPRO}
${Q}minipro -p ${ROM_PART_ID} -w ${ROM_FILE}
################################################################################
#### CLEAN-UP ####
################################################################################
.PHONY: clean
clean:
$(call QUIET_CLEAN,system)
${Q}rm -rf ${SYSTEM_VVP} *.fst boot_code.txt boot_code.bin *memdump *memdumptxt obj_dir
${Q}rm -rf ${SYSTEM_VVP} *.fst boot_code.txt boot_code.bin *memdump *memdumptxt obj_dir simplified_ucode.txt abc.history build
.PHONY: mrproper
mrproper:
$(call QUIET_MRPROPER,system)
${Q}rm -f external_ip/litedram_core_ecp5_phy.v external_ip/litedram_core_ecp5_phy_sim.v

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -47,10 +47,10 @@ always @ ( * ) begin
`ALU_OP_ADD_SIGNED_B: {C_FLAG,OUT[7:0]}=A[7:0]+SIGNED_8B;
`ALU_OP_SUB: {C_FLAG,OUT[7:0]}=A[7:0]-B[7:0];
`ALU_OP_SUB_REVERSE: {C_FLAG,OUT[7:0]}=B[7:0]-A[7:0];
`ALU_OP_AND: begin C_FLAG=0;OUT=A&B; end
`ALU_OP_OR: begin C_FLAG=0;OUT=A|B; end
`ALU_OP_XOR: begin C_FLAG=0;OUT=A^B; end
`ALU_OP_SHIFT_LEFT: begin C_FLAG=(A&16'h80)==16'h80;OUT=A<<B; end
`ALU_OP_AND: begin C_FLAG=0;OUT[7:0]=A[7:0]&B[7:0]; end
`ALU_OP_OR: begin C_FLAG=0;OUT[7:0]=A[7:0]|B[7:0]; end
`ALU_OP_XOR: begin C_FLAG=0;OUT[7:0]=A[7:0]^B[7:0]; end
`ALU_OP_SHIFT_LEFT: begin C_FLAG=(A&16'h80)==16'h80;OUT[7:0]=A[7:0]<<B; end
endcase
end
end

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

385
system/biu.v Normal file
View File

@ -0,0 +1,385 @@
/* biu.v - implementation of the 9086 bus interface unit. The logic that
controls all external bus functions
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`include "config.v"
`define BIU_HALT 4'b0000
`define BIU_NEXT_ACTION 4'b0001
`define BIU_READ 4'b0010
`define BIU_RESET1 4'b0011
`define BIU_RESET2 4'b1111
`define BIU_PUT_BYTE 4'b0100
`define BIU_PUT_UNALIGNED_16BIT_DATA 4'b0101
`define BIU_PUT_ALIGNED_16BIT_DATA 4'b0110
`define BIU_PUT_UNALIGNED_PREP_NEXT2 4'b1000
`define BIU_WRITE_EXIT 4'b1001
`define BIU_WRITE_RELEASE 4'b1010
`define BIU_GET_ALIGNED_DATA 4'b1011
`define BIU_GET_UNALIGNED_DATA 4'b1100
`define BIU_GET_SECOND_BYTE 4'b1101
`define BIU_GET_SECOND_BYTE1 4'b1110
module BIU (
/***************** GENERAL *****************/
/* */ input clock, input reset
/**************** OUTSIDE WORLD ****************/
/* */ ,output wire [19:0] external_address_bus
/* */ ,input [15:0] external_data_bus_read,output [15:0] external_data_bus_write,output reg read, output reg write,output reg BHE,output reg IOMEM
/* */ ,input wait_state
/**************** OUTPUT TO DE ****************/
/* */ ,output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION
/* */ ,output reg VALID_DATA
/**************** INPUT FROM DE ****************/
,input Wbit, input MEM_OR_IO, input valid_instruction_ack
/**************** INPUT FROM EX ****************/
/* */ ,input jump_req, input write_request, input read_request
/* */ ,input[15:0] ADDRESS_INPUT, input [15:0] DATA_EX_WRITE
/**************** OUTPUT TO EX *****************/
/* */ ,output [15:0] DATA_EX_READ
`ifdef OUTPUT_JSON_STATISTICS
/***************** STATISTICS *****************/
/* */ ,output wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE_STAT, output wire VALID_INSTRUCTION_STAT
`endif
);
`ifdef OUTPUT_JSON_STATISTICS
assign FIFO_SIZE_STAT = FIFO_SIZE;
assign VALID_INSTRUCTION_STAT = ((Isit1==1) && (FIFO_SIZE!=0) && `EARLY_VALID_INSTRUCTION_) || ((fifoIsize==2) && (FIFO_SIZE > 1) && `EARLY_VALID_INSTRUCTION_) || ((fifoIsize==3) && (FIFO_SIZE > 2) && `EARLY_VALID_INSTRUCTION_) || (FIFO_SIZE>3);
`endif
reg [15:0] data_bus_output_register;
assign external_data_bus_write=data_bus_output_register; //TODO: should we rename?
reg [15:0] DATA_OUT;
assign DATA_EX_READ=DATA_OUT; //TODO should we rename?
`define FIFO_SIZE_BYTES $rtoi($pow(2,`L1_CACHE_SIZE))
reg [7:0] INPUT_FIFO [`FIFO_SIZE_BYTES-1:0];
reg [`L1_CACHE_SIZE-1:0] FIFO_start; /*inclusive*/
reg [`L1_CACHE_SIZE-1:0] FIFO_end; /*exclusive*/
wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE = FIFO_end-FIFO_start;
reg [3:0] biu_state;
reg sane;
reg func;
reg [19:0]INSTRUCTION_ADDRESS;
reg [19:0]DATA_ADDRESS;
assign external_address_bus= func ? INSTRUCTION_ADDRESS : DATA_ADDRESS ;
always @(posedge clock) begin
if ( reset == 0 ) begin
biu_state <= `BIU_HALT;
write <= 1;
sane <= 0;
biu_state <= `BIU_RESET1;
FIFO_start <= `L1_CACHE_SIZE'b0;
FIFO_end <= `L1_CACHE_SIZE'b0;
end else if ( jump_req ) begin
FIFO_start <= FIFO_end ;
INSTRUCTION_ADDRESS <= { 4'hF , ADDRESS_INPUT };
INSTRUCTION_LOCATION <= ADDRESS_INPUT;
func <= 1;
if (biu_state==`BIU_READ)
biu_state <= `BIU_NEXT_ACTION;
end else if(valid_instruction_ack) begin
FIFO_start <= FIFO_start + {{`L1_CACHE_SIZE-3{1'b0}},Isize};
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {13'd0,Isize};
end else if (wait_state==1)begin
// nothing...
end else begin
case(biu_state)
`BIU_HALT: begin
end
`BIU_NEXT_ACTION: begin /* decide if we can read, if we are full or if we need to do something else */
if (write_request) begin
func<=0;
DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT };
IOMEM <= MEM_OR_IO;
biu_state <= (Wbit==0) ? `BIU_PUT_BYTE : (ADDRESS_INPUT[0:0]?`BIU_PUT_UNALIGNED_16BIT_DATA:`BIU_PUT_ALIGNED_16BIT_DATA) ;
INSTRUCTION_ADDRESS <= {4'hF,INSTRUCTION_LOCATION} ;
FIFO_end<=FIFO_start;
end else if ( read_request ) begin
func<=0;
DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT };
IOMEM <= MEM_OR_IO;
read <= 0;
BHE <= 0;
biu_state <= (ADDRESS_INPUT[0:0])?`BIU_GET_UNALIGNED_DATA:`BIU_GET_ALIGNED_DATA;
end else begin
if ( FIFO_SIZE!={`L1_CACHE_SIZE{1'b1}} ) begin
func<=1;
biu_state <= `BIU_READ;
write <= 1;
read <= 0;
IOMEM <= 0;
BHE <= 0;
end else begin
biu_state <= `BIU_NEXT_ACTION;
end
end
end
/*************** INSTRUCTION FIFO READ ***************/
`BIU_READ: begin
if(INSTRUCTION_ADDRESS[0:0]==0 && FIFO_SIZE<{{(`L1_CACHE_SIZE-1){1'b1}},1'b0})begin
INPUT_FIFO[FIFO_end] <= external_data_bus_read[7:0];
INPUT_FIFO[FIFO_end+`L1_CACHE_SIZE'd1] <= external_data_bus_read[15:8];
FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd2;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd2;
end else if(INSTRUCTION_ADDRESS[0:0]==0)begin
INPUT_FIFO[FIFO_end] <= external_data_bus_read[7:0];
FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd1;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1;
end else begin
INPUT_FIFO[FIFO_end] <= external_data_bus_read[15:8];
FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd1;
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1;
end
biu_state <= `BIU_NEXT_ACTION;
read<=1;
end
/*************** DATA WRITE ***************/
`BIU_PUT_UNALIGNED_16BIT_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES
$display("Writing 16bit %04x at %04x",DATA_EX_WRITE,DATA_ADDRESS);
`endif
BHE <= 0;
data_bus_output_register <= {DATA_EX_WRITE[7:0],DATA_EX_WRITE[15:8]};
write <= 0;
biu_state <= `BIU_PUT_UNALIGNED_PREP_NEXT2;
end
`BIU_PUT_UNALIGNED_PREP_NEXT2:begin
write <= 1;
DATA_ADDRESS <= DATA_ADDRESS+20'd1;
BHE <= 1;
biu_state <= `BIU_WRITE_EXIT;
end
`BIU_PUT_ALIGNED_16BIT_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES
$display("Writing 16bit %04x at %04x",DATA_EX_WRTIE,DATA_ADDRESS);
`endif
data_bus_output_register <= {DATA_EX_WRITE[15:8],DATA_EX_WRITE[7:0]};
write <= 0;
biu_state <= `BIU_WRITE_RELEASE;
end
`BIU_PUT_BYTE:begin
`ifdef DEBUG_DATA_READ_WRITES
$display("Writing 8bit %02x at %04x",DATA_EX_WRITE[7:0],DATA_ADDRESS);
`endif
if(ADDRESS_INPUT[0:0]==0) begin
BHE <= 1;
data_bus_output_register <= {8'b0,DATA_EX_WRITE[7:0]};
end else begin
BHE <= 0;
data_bus_output_register <= {DATA_EX_WRITE[7:0],8'b0};
end
write <= 0;
biu_state <= `BIU_WRITE_RELEASE;
end
`BIU_WRITE_EXIT:begin
write <= 0;
biu_state <= `BIU_WRITE_RELEASE;
end
`BIU_WRITE_RELEASE:begin
write <= 1;
biu_state <= `BIU_NEXT_ACTION;
end
/*************** DATA READ ***************/
`define finished_read \
if ( read_request == 0 ) begin \
biu_state <= `BIU_NEXT_ACTION;\
VALID_DATA <= 0;\
end else \
VALID_DATA <= 1;
`BIU_GET_ALIGNED_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES
if(Wbit==1)
$display("Reading 16bit %04x from %04x",external_data_bus_read,DATA_ADDRESS);
else
$display("Reading 8bit %02x from %04x",external_data_bus_read[7:0],DATA_ADDRESS);
`endif
DATA_OUT <= (Wbit==1)? external_data_bus_read : {8'b0,external_data_bus_read[7:0]} ;
read <=1;
`finished_read
end
`BIU_GET_UNALIGNED_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES
if(Wbit==0)
$display("Reading 8bit %02x from %04x",external_data_bus_read[15:8],DATA_ADDRESS);
`endif
DATA_OUT[7:0] <= external_data_bus_read[15:8];
read <=1;
if(Wbit==1) begin
biu_state <= `BIU_GET_SECOND_BYTE;
end else begin
`finished_read
end
end
`BIU_GET_SECOND_BYTE:begin
DATA_ADDRESS <= DATA_ADDRESS+20'd1;
biu_state <= `BIU_GET_SECOND_BYTE1;
read <=0;
end
`BIU_GET_SECOND_BYTE1:begin
`ifdef DEBUG_DATA_READ_WRITES
$display("Reading 16bit %02x from %04x",{external_data_bus_read[7:0],DATA_OUT[7:0]},DATA_ADDRESS-1);//read started a byte earlier
`endif
DATA_OUT[15:8] <= external_data_bus_read[7:0];
`finished_read
read <=1;
end
/*************** HOUSE KEEPING ***************/
`BIU_RESET1: begin
biu_state <= `BIU_RESET2;
VALID_DATA <= 0;
end
`BIU_RESET2: begin
FIFO_start <= `L1_CACHE_SIZE'b0;
FIFO_end <= `L1_CACHE_SIZE'b0;
biu_state <= `BIU_NEXT_ACTION;
INSTRUCTION_ADDRESS <= 20'hFFFF0;
INSTRUCTION_LOCATION <= 16'hFFF0;
VALID_DATA <= 0;
sane<=1;
end
default: begin
biu_state <= `BIU_NEXT_ACTION;/*Should be unreachable*/
end
endcase
end
end
/* update VALID_INSTRUCTION and INSTRUCTION */
always @( posedge clock) begin
if(jump_req==1)begin
VALID_INSTRUCTION <= 0;
end else if(sane==1) begin
//if(VALID_INSTRUCTION == 1 ) begin
// `ifdef DOUBLE_INSTRUCTION_LOAD
// if(FIFO_SIZE>`L1_CACHE_SIZE'd3+{{`L1_CACHE_SIZE-3{1'b0}},Isize})begin
// if((fifoIsize2==2) && (FIFO_SIZE > `L1_CACHE_SIZE'd1+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize}))begin
// VALID_INSTRUCTION <= 1;
// INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
// INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
// end else if((fifoIsize2==3) && (FIFO_SIZE > `L1_CACHE_SIZE'd2+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize}))begin
// VALID_INSTRUCTION <= 1;
// INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
// INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
// INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
// end else if(FIFO_SIZE>`L1_CACHE_SIZE'd3+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize})begin
// VALID_INSTRUCTION <= 1;
// INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
// INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
// INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
// INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3];
// end else
// VALID_INSTRUCTION <= 0;
// end else begin
// VALID_INSTRUCTION <= 0;
// end
// `else
// VALID_INSTRUCTION <= 0;
// `endif
//end else begin
//$display("trig fifoIsize=%d %d/%d [%02x %02x]",fifoIsize,FIFO_start,FIFO_end,INPUT_FIFO[FIFO_start],INPUT_FIFO[FIFO_start+1]);
`ifdef EARLY_VALID_INSTRUCTION
if(FIFO_start==FIFO_end) begin
/*TODO: I would use FIFO_SIZE==0 here or better yet add an else at the
end but since FIFO_start and FIFO_end are updated in a blocking
manner it seems that the assign statement updating FIFO_SIZE
doesn't work. PLEASE CLEAN UP THIS MESS */
VALID_INSTRUCTION <= 0;
end else if((Isit1==1) && (FIFO_SIZE!=0))begin
VALID_INSTRUCTION <= 1;
INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
end else if((fifoIsize==2) && (FIFO_SIZE > `L1_CACHE_SIZE'd1))begin
VALID_INSTRUCTION <= 1;
INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
end else if((fifoIsize==3) && (FIFO_SIZE > `L1_CACHE_SIZE'd2))begin
VALID_INSTRUCTION <= 1;
INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
end else if(FIFO_SIZE > `L1_CACHE_SIZE'd3)begin
VALID_INSTRUCTION <= 1;
INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3];
end else
VALID_INSTRUCTION <= 0;
`else
if(FIFO_start==FIFO_end) begin
/*TODO: Same as on the first statement on the other side of the `ifdef */
VALID_INSTRUCTION <= 0;
end else if(FIFO_SIZE>`L1_CACHE_SIZE'd3)begin
VALID_INSTRUCTION <= 1;
INSTRUCTION[31:24] <= INPUT_FIFO[FIFO_start];
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3];
end else
VALID_INSTRUCTION <= 0;
`endif
//end
end
end
wire [2:0] Isize;
InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize);
`ifdef INCLUDE_EARLY_CALC_CIRCUIT
wire [2:0] fifoIsize;
wire Isit1;
InstrSize fifoInstrSize({INPUT_FIFO[FIFO_start][7:0],INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1][5:3]},fifoIsize);
Is1 Is1(INPUT_FIFO[FIFO_start][7:0],Isit1);
`endif
`ifdef DOUBLE_INSTRUCTION_LOAD
wire [2:0] fifoIsize2;
InstrSize fifoInstrSize2(
{ INPUT_FIFO[FIFO_start+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize}][7:0], INPUT_FIFO[FIFO_start+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize}+`L1_CACHE_SIZE'd1][5:3]}
,fifoIsize2
);
`endif
endmodule

View File

@ -1,8 +1,4 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
.ORG 0x0100
.ORG 0xFF00
start:
MOV SP,#STACK
MOV AX,#0x0000
@ -25,16 +21,15 @@ dec [si]
dec cx
cmp CX,#0x00
MOV CH,#0x9A
TEST CH,#0x70
inw #0x20
CMP AX,#0xABCD
jz WAZZ
mov ah,#2
mov dl,#'1
int #0x21
mov al,#'0
out byte #0xA5
hlt
WAZZ:
mov ah,#2
mov dl,#'0
int #0x21
mov al,#'1
out byte #0xA5
hlt
TEST_:
ADD AX,#0xDEAD
@ -52,5 +47,5 @@ iret
STACK:
.ORG 0xFFF0
MOV AX,#0x0100
MOV AX,#0xFF00
JMP AX

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,7 +17,66 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
//Runtime Verbosity
/** Runtime Verbosity **/
//`define DEBUG_REG_WRITES
//`define DEBUG_PC_ADDRESS
//`define DEBUG_MEMORY_WRITES
//`define DEBUG_DATA_READ_WRITES
/** OUTPUT **/
/* These are usually set at build time*/
//`define CALCULATE_IPC
//`define OUTPUT_JSON_STATISTICS
/** Optimisations **/
/* Enables the ability to check if an instruction in the input
* buffer is completed and mark it ready instead of always waiting
* for the maximum instruction size worth of bytes */
`define EARLY_VALID_INSTRUCTION
/*********** CURRENTLY DOESN'T WORK *************/
/* Enables the ability in BIU to pre-decode two instructions, one after the other in memory*/
//`define DOUBLE_INSTRUCTION_LOAD
/************************************************/
/* Size is in powers of two with minimal 3.
* 3 : 8 Bytes
* 4 : 16 Bytes
* 5 : 32 Bytes
* . : ... */
`define L1_CACHE_SIZE 4
// Use high impedance instead of some other undefined value
// when a signal is invalid (for example a data port when a
// memory is not selected). This could be used for debug
//`define USE_HIGH_IMPEDANCE
/********** Internal **********/
`ifdef SYNTHESIS
`undef DEBUG_REG_WRITES
`undef DEBUG_PC_ADDRESS
`undef DEBUG_DATA_READ_WRITES
`undef CALCULATE_IPC
`undef OUTPUT_JSON_STATISTICS
`endif
`ifdef OUTPUT_JSON_STATISTICS
`define CALCULATE_IPC
`endif
`ifdef DOUBLE_INSTRUCTION_LOAD
/*Needed for DOUBLE_INSTRUCTION_LOAD*/
`define EARLY_VALID_INSTRUCTION
`endif
`ifdef EARLY_VALID_INSTRUCTION
`define INCLUDE_EARLY_CALC_CIRCUIT
`define EARLY_VALID_INSTRUCTION_ 1
`else
`define EARLY_VALID_INSTRUCTION_ 0
`endif
`ifdef CALCULATE_IPC
`define INCLUDE_EARLY_CALC_CIRCUIT
`endif

File diff suppressed because it is too large Load Diff

4
system/error_header.v Normal file
View File

@ -0,0 +1,4 @@
`define ERROR_BITS 3
`define ERR_NO_ERROR 3'b000
`define ERR_UNIMPL_INSTRUCTION 3'b001
`define ERR_UNIMPL_ADDRESSING_MODE 3'b010

46
system/exec_state_def.v Normal file
View File

@ -0,0 +1,46 @@
/* exec_state_def.v - Definitions of the states in the main state machine
of the 9086 CPU.
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`define EXEC_STATE_BITS 4
//TODO: Please clean this up
`define EXEC_WAIT 4'b1100
/*DECODE SATE*/
`define EXEC_DE_LOAD_REG_TO_PARAM 4'b0011
/*MEM/IO READ*/
`define EXEC_MEMIO_READ 4'b0101
`define EXEC_MEMIO_READ_SETADDR 4'b0110
/*EXECUTE STATE*/
`define EXEC_WRITE_ENTRY 4'b1000
/*MEM/IO WRITE*/
`define EXEC_MEMIO_WRITE 4'b0111
`define EXEC_NEXT_INSTRUCTION 4'b1001
`define EXEC_NEXT_MICROCODE 4'b1010
`define EXEC_RESET 4'b1011
`define EXEC_JUMP_RELEASE 4'b1101

324
system/execute.v Normal file
View File

@ -0,0 +1,324 @@
/* execute.v - Implements the instruction execution logic
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`include "exec_state_def.v"
`include "alu_header.v"
`include "error_header.v"
module execute_unit (
/***************** GENERAL *****************/
/* */ input clock, input reset, input write /*TODO: REMOVE!!*/, output reg [`ERROR_BITS-1:0] ERROR
/*************** INPUT FROM DE ***************/
/* SYNC SIGNALS */ ,input valid_input,input set_initial_values
/* INSTR. PARAMS */ ,input Wbit ,input [2:0] IN_MOD, input [2:0] OUT_MOD, input [2:0] RM
/* DATA */ ,input [15:0] PARAM1_INIT, input [15:0] PARAM2_INIT, input [15:0] ProgCount
/* STATE CONTROL */ ,input [`EXEC_STATE_BITS-1:0] init_state
/* ALU CONTROL */ ,input [1:0] in_alu_sel1, input [1:0] in_alu_sel2, input [`ALU_OP_BITS-1:0] ALU_OP, output [15:0] _ALU_O_
/* OTHER */ ,input memio_address_select
/**************** OUTPUT TO DE ****************/
/* SYNC SIGNALS */ ,output reg next_exec
/* FLAGS */ ,output reg [7:0] EX2DE_FLAGS
/**************** OUTPUT TO BIU ****************/
/* */ ,output reg [15:0] BIU_ADDRESS_INPUT
/* */ ,output reg biu_read_request, output reg biu_jump_req,output reg biu_write_request
/*************** INPUT FROM BIU ****************/
/* */ ,input BIU_VALID_DATA,input [15:0] BIU_EX_DATA_READ
/**************** OUTPUT TO BIU ****************/
/* */ ,output [15:0] BIU_EX_DATA_WRITE
/***************** REGISTERS *****************/
/* */ ,input [15:0] reg_read_port1_data ,input [15:0] reg_read_port2_data, output reg [3:0] reg_read_port1_addr
/* */ ,output reg use_exec_reg_addr, output reg reg_write_we
);
assign _ALU_O_ = ALU_O;
reg [`EXEC_STATE_BITS-1:0] exec_state;
reg [15:0] PARAM1,PARAM2;
assign BIU_EX_DATA_WRITE = memio_address_select ? reg_read_port1_data : ALU_O;
/*############ ALU / Execution units ################################################## */
mux4 #(.WIDTH(16)) MUX16_1A(
/*0*/ PARAM1,
/*1*/ reg_read_port1_data,
/*2*/ ProgCount[15:0],
/*3*/ 16'd0, /*0 Constant*/
in_alu_sel1,
ALU_A);
mux4 #(.WIDTH(16)) MUX16_1B(
/*0*/ PARAM2,
/*1*/ reg_read_port2_data,
/*2*/ ProgCount[15:0],
/*3*/ 16'd0, /*0 Constant*/
in_alu_sel2,
ALU_B);
wire [15:0] ALU_A;
wire [15:0] ALU_B;
wire [15:0] ALU_O;
wire [7:0] ALU_FLAGS;
ALU ALU1(
/* INPUT 1 */ .A(ALU_A),
/* INPUT 2 */ .B(ALU_B),
/* OUTPUT */ .OUT(ALU_O),
/* OPERATION */ .op(ALU_OP),
/* FLAGS */ .FLAGS(ALU_FLAGS),
/* Wbit */ .Wbit(Wbit)
);
/*############ Execute logic ########################################################## */
`define unimpl_addressing_mode exec_state <= `EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;
`define finished_instruction exec_state <= `EXEC_WAIT;next_exec<=1;
always @(posedge clock) begin
if ( !reset ) begin
exec_state <= `EXEC_RESET;
end else begin
if ( set_initial_values )begin
PARAM1 <= PARAM1_INIT;
PARAM2 <= PARAM2_INIT;
end
begin
case (exec_state)
`EXEC_RESET: begin
biu_write_request <= 0;
biu_read_request <= 0;
biu_jump_req <= 0;
reg_write_we <= 1;
exec_state <= `EXEC_WAIT;
ERROR <= `ERR_NO_ERROR;
end
`EXEC_WAIT:begin
if(valid_input)begin
exec_state <= init_state;
next_exec<=0;
end else begin
next_exec<=1;
end
biu_jump_req <= 0;
reg_write_we <= 1;
use_exec_reg_addr <= 0;
ERROR<=`ERR_NO_ERROR;
end
`EXEC_DE_LOAD_REG_TO_PARAM:begin
PARAM2<=reg_read_port2_data;
case(IN_MOD)
3'b000,3'b001,3'b010: exec_state <= `EXEC_MEMIO_READ;
default: exec_state <= `EXEC_WRITE_ENTRY;
endcase
end
`EXEC_MEMIO_READ:begin
/*Decode MOD R/M, read the data and place it to PARAM1*/
case (IN_MOD)
3'b000,
3'b001,
3'b010:begin
case (RM)
3'b000:begin
/*[BX]+[SI]*/
`unimpl_addressing_mode
end
3'b001:begin
/*[BX]+[SI]*/
`unimpl_addressing_mode
end
3'b010:begin
/*[BP]+[SI]*/
`unimpl_addressing_mode
end
3'b011:begin
/*[BP]+[DI]*/
`unimpl_addressing_mode
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_READ_SETADDR;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_READ_SETADDR;
end
3'b110:begin
/*d16 */
`unimpl_addressing_mode
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_READ_SETADDR;
end
endcase
if(IN_MOD!=3'b000)begin
/*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/
`unimpl_addressing_mode;
end
end
3'b110:begin /* SP Indirect read*/
reg_read_port1_addr <= 4'b1100;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_READ_SETADDR;
end
default:begin
`unimpl_addressing_mode
end
endcase
end
`EXEC_MEMIO_READ_SETADDR:begin
/* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */
/* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */
if(memio_address_select==0)
BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0];
else
BIU_ADDRESS_INPUT <= ALU_O;
if ( BIU_VALID_DATA == 1 ) begin
exec_state <= `EXEC_WRITE_ENTRY;
PARAM2 <= BIU_EX_DATA_READ;
biu_read_request <= 0;
end else begin
biu_read_request <= 1;
end
end
`EXEC_NEXT_INSTRUCTION:begin
`finished_instruction
/*necessary for biu to see we went on another state from decode to give us a new instruction*/
end
`EXEC_WRITE_ENTRY:begin
EX2DE_FLAGS[7:0] <= ALU_FLAGS[7:0];
case(OUT_MOD)
3'b000,
3'b001,
3'b010 : begin
if(memio_address_select==1)
exec_state <= `EXEC_MEMIO_WRITE;
else
case (RM) /* Duplicate code with write... */
3'b000:begin
/*[BX]+[SI]*/
`unimpl_addressing_mode
end
3'b001:begin
/*[BX]+[SI]*/
`unimpl_addressing_mode
end
3'b010:begin
/*[BP]+[SI]*/
`unimpl_addressing_mode
end
3'b011:begin
/*[BP]+[DI]*/
`unimpl_addressing_mode
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_WRITE;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_WRITE;
end
3'b110:begin
/*d16 */
`unimpl_addressing_mode
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_WRITE;
end
endcase
end
3'b011:begin
reg_write_we <= 0;
`finished_instruction
end
3'b100:begin /*No output*/
`finished_instruction
end
3'b101:begin /* Program Counter*/
BIU_ADDRESS_INPUT <= ALU_O[15:0];
biu_jump_req <= 1;
exec_state <= `EXEC_JUMP_RELEASE;
end
3'b110:begin /* SP Indirect write*/
reg_read_port1_addr <= 4'b1100;
use_exec_reg_addr <= 1;
exec_state <= `EXEC_MEMIO_WRITE;
end
3'b111:begin /* Write to PRAM1 (for microcode calculations) */
PARAM1 <= ALU_O;
`finished_instruction
end
default:begin
`unimpl_addressing_mode
end
endcase
end
`EXEC_JUMP_RELEASE:begin
biu_jump_req <= 0;
`finished_instruction
end
`EXEC_MEMIO_WRITE:begin
/* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */
/* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */
biu_write_request <= 1;
if(memio_address_select==0)
BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0];
else
BIU_ADDRESS_INPUT <= ALU_O;
if (write == 0) begin //TODO: don't do it that way or better yet don't do it at all somehow
biu_write_request <= 0;
`finished_instruction
end
end
default:begin
end
endcase
end
end
end
endmodule
`undef unimpl_addressing_mode

0
system/external_ip/.keep Normal file
View File

View File

@ -0,0 +1,39 @@
#### ECP5 specific ####
ECP5_DEVICE=25F
# ECP5_DEVICE: 25F: Create bitstream for the LFE5U-25F
# 85F: Create bitstream for the LFE5U-85F
ECP5_PACKAGE=CSFBGA285
# ECP5_PACKAGE: CSFBGA285: The one used in OrangeCrab
FPGA_FILE_EXT=dfu
#This is on the 8th postiion in the chip id, for example
# LFE5U-25-7BG381I
# ^---------- this would be a 7 speed grade
#
# 6 is the slowest and 8 is the fastest
ECP5_SPEED_GRADE=8
ROM_PART_ID=24lc512
######## End of user configuration ########
#NOT USED OUTSIDE OF HERE
FPGA_SOC_COMMON_SOURCES=peripherals/I2C_driver.v peripherals/ascii_to_HD44780_driver.v peripherals/pcf8574_for_HD44780.v peripherals/Wishbone_IO_driver.v peripherals/Wishbone_memory_driver.v peripherals/I2C_driver_multiplexer.v peripherals/CPU_to_I2C_driver_bridge.v
FPGA_SOC_SOURCES=${FPGA_SOC_COMMON_SOURCES} external_ip/litedram_core_ecp5_phy.v
FPGA_SOC_SIM_SOURCES=${FPGA_SOC_COMMON_SOURCES} fpga_config/OrangeCrab_r0.2.1/verilator_config.vlt external_ip/litedram_core_ecp5_phy_sim.v
FPGA_BOOTCODE=../boot_code/i2c_bootloader.stxt
ROM_FILE=../boot_code/brainfuck_mandelbrot.bin
upload_bitstream: dfu_upload
upload_bootrom: minipro_upload
${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.bit:${BUILD_FILES_PREFIX}nextpnr-ecp5_${BUILD_NAME}.bit
${Q}cp "$^" "$@"
${BUILD_FILES_PREFIX}synth_${FPGA_BOARD}.json:${BUILD_FILES_PREFIX}synth_ecp5_${FPGA_BOARD}.json
${Q}cp "$^" "$@"

View File

@ -0,0 +1,630 @@
/* top.v - Implements FPGA and Board specific circuitry
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`include "error_header.v"
`ifdef OUTPUT_JSON_STATISTICS
`include "config.v"
`endif
module fpga_top(
input clk48,
input user_button,
// output reset_n,
output rgb_led0_r,
output rgb_led0_g,
output rgb_led0_b,
`ifdef SYNTHESIS
output wire [15:0] ddram_a, // [15:13] are unused in litex as well, they just also route them through a trellis block
output wire [2:0] ddram_ba,
output wire ddram_cas_n,
output wire ddram_cke,
output wire ddram_clk_p,
output wire ddram_cs_n,
output wire [1:0] ddram_dm,
input wire [15:0] ddram_dq,
input wire [1:0] ddram_dqs_p,
output wire [1:0] ddram_gnd,
output wire ddram_odt,
output wire ddram_ras_n,
output wire ddram_reset_n,
output wire [5:0] ddram_vccio,
output wire ddram_we_n,
inout i2c_sda,/*sda*/
output i2c_scl /*scl*/
`else
output i2c_dir,
output i2c_scl,
input i2c_sda_in,
output i2c_sda_out
`endif
);
`ifndef SYNTHESIS
string waveform_name;
initial begin
if($value$plusargs("WAVEFORM=%s",waveform_name))begin
$dumpfile(waveform_name);
$dumpvars(0,p,cycles);
end
end
//TODO: should there be some common file between all the fpga_tops and system.v for this stuff?
always @(posedge clk48) begin
if(HALT==1&&disp_cache_start==disp_cache_end)begin
$finish;
end
end
reg sane;
always @(posedge reset)begin sane<=1; end
always @( ERROR ) begin
if ( ERROR != `ERR_NO_ERROR && sane == 1 ) begin
$display("PROCESSOR RUN INTO AN ERROR.");
case (ERROR)
default:begin
end
`ERR_UNIMPL_INSTRUCTION:begin
$display("Unimplemented instruction");
end
`ERR_UNIMPL_ADDRESSING_MODE: begin
$display("Unimplemented addressing mode");
end
endcase
$finish;
end
end
`endif
`ifdef SYNTHESIS
assign ddram_a[15:13] = 3'b0;
assign ddram_vccio = 6'd63;
assign ddram_gnd = 2'd0;
`endif
wire HALT;
wire [`ERROR_BITS-1:0]ERROR;
wire [19:0] address_bus;
wire [15:0] data_bus_read,data_bus_write;
wire rd,wr,BHE,IOMEM;
wire CPU_SPEED;
processor p(
.clock(CPU_SPEED),
.reset(reset),
.HALT(HALT),
.ERROR(ERROR),
.external_address_bus(address_bus),
.external_data_bus_read(data_bus_read),
.external_data_bus_write(data_bus_write),
.wait_state(wait_state),
.read(rd),
.write(wr),
.BHE(BHE),
.IOMEM(IOMEM)
`ifdef CALCULATE_IPC
/* STATISTICS */ ,.new_instruction(new_instruction)
`endif
`ifdef OUTPUT_JSON_STATISTICS
/* */ ,.L1_SIZE_STAT(L1_SIZE_STAT), .VALID_INSTRUCTION_STAT(VALID_INSTRUCTION_STAT), .jump_req_debug(jump_req_debug)
`endif
);
/* verilator lint_off UNUSEDSIGNAL */
`ifdef CALCULATE_IPC
wire new_instruction;
`endif
`ifdef OUTPUT_JSON_STATISTICS
wire [`L1_CACHE_SIZE-1:0]L1_SIZE_STAT;
wire VALID_INSTRUCTION_STAT;
wire jump_req_debug;
`endif
/* verilator lint_on UNUSEDSIGNAL */
reg [2:0]rgb_led_color;
assign rgb_led0_r=rgb_led_color[0];
assign rgb_led0_g=rgb_led_color[1];
assign rgb_led0_b=rgb_led_color[2];
// A bit useless since if the cpu ERRORS out or HALTS it will continue executing anyway
//always @(HALT or ERROR or user_button) begin
// if (HALT==1) begin
// /* yellow */
// rgb_led_color<=3'b100;
// end else if (ERROR != `ERROR_BITS'b0) begin
// /* red */
// rgb_led_color<=3'b110;
// end else begin
// /* green */
// rgb_led_color<=3'b101;
// end
//end
// Create a 27 bit register
reg [26:0] counter = 0;
// Every positive edge increment register by 1
always @(posedge clk48) begin
counter <= counter + 1;
end
/*** RESET CIRCUIT ***/
reg reset=0;
reg [1:0] state=0;
always @(posedge counter[15]) begin
if(user_button==0)
state<=2'b00;
case (state)
2'b00:begin
reset<=0;
state<=2'b01;
end
2'b01:begin
reset<=1;
state<=2'b10;
end
default: begin
end
endcase
end
//------------------------------------------//
// Cache to allow the slow display to have a
// chance to keep up with the relentless CPU
reg [7:0] disp_cache_start=0;
reg [7:0] disp_cache_end=0;
reg [7:0] disp_write_cache [255:0];
reg ascii_state=0;
always @(posedge CPU_SPEED)begin
if(wr==0)begin
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
disp_write_cache[disp_cache_end]<=data_bus_write[15:8];
disp_cache_end<=disp_cache_end+8'd1;
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
if(data_bus_write[0:0]==1)
rgb_led_color<=3'b000;
else
rgb_led_color<=3'b111;
end
end else if(ascii_state==1'b0)begin
if(ascii_data_ready&disp_cache_start!=disp_cache_end)begin
`ifndef SYNTHESIS
$write("%s" ,disp_write_cache[disp_cache_start]); // TODO: maybe simulate the i2c lcd
`endif
ascii_data<=disp_write_cache[disp_cache_start];
disp_cache_start<=disp_cache_start+8'd1;
ascii_data_write_req<=1;
ascii_state<=1'b1;
end
end
if(ascii_state==1'b1)begin
if(!ascii_data_ready)begin
ascii_data_write_req<=0;
ascii_state<=1'b0;
end
end
end
wire I2C_SPEED=counter[7];
wire [15:0]boot_rom_data_bus_read;
wire [15:0]boot_rom_data_bus_write;
assign boot_rom_data_bus_write=data_bus_write;
wire boot_rom_cs_n;
doublemem #( .RAM_SIZE_IN_BYTES(2048) ) boot_rom
( address_bus[10:0],boot_rom_data_bus_read,boot_rom_data_bus_write,rd,wr,BHE,boot_rom_cs_n,CPU_SPEED );
/// Memory Map
assign data_bus_read = ( IOMEM == 1 ) ? data_bus_read_IO : data_bus_read_MEM ;
wire [15:0] data_bus_read_IO = ( address_bus[7:1] == 7'h10 ) ? LITEDRAM_STATUS_REGISTER : ( (address_bus[7:4] == 4'h4) ? Wishbone_driver_data_bus_read:CPU_I2C_data_bus_read);
assign boot_rom_cs_n = !((IOMEM==0)&&(address_bus[15:12]==4'hF));
wire [15:0] data_bus_read_MEM = (address_bus[15:12]==4'hF)? boot_rom_data_bus_read:data_bus_read_DDR3;
wire DDR3_ram_cs = (IOMEM==0)&&(address_bus[15:12]!=4'hF);
//
// 0x20 | DDR STATUS BYTE1 |
// 0x21 | DDR STATUS BYTE1 |
// | |
// - | -- |
// | |
// 0x30 | WISHBONE |
// .. | .. |
// 0x3F | WISHBONE |
//
assign wishbone_cs=!((IOMEM==1)&&(address_bus[7:4] == 4'h4));
assign i2c_cs= !((IOMEM==1)&&(address_bus[7:4] == 4'h6));
assign wait_state_I2C=(i2c_cs==1'b0&&rd==1'b0)^i2c_cs_1d;
reg i2c_cs_1d;
always @(posedge CPU_SPEED)begin
i2c_cs_1d<=(i2c_cs==1'b0&&rd==1'b0);
end // TODO: Probably would need to so the same for the wishbone IO
wire wait_state_I2C;
/// DDR3 Controller
wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked;
/* verilator lint_off UNUSEDSIGNAL */
wire user_rst;
/* verilator lint_on UNUSEDSIGNAL */
`ifndef SYNTHESIS
assign ddr3_pll_locked=1;
wire sim_trace;
assign sim_trace=0;//signal is not connected on litedram, not sure what was the idea behind it
`endif
wire [15:0]Wishbone_driver_data_bus_read;
wire [15:0]Wishbone_driver_data_bus_write=data_bus_write;
wire wishbone_cs;
Wishbone_IO_driver Wishbone_IO_driver(
///// GENERAL //////
.clock(CPU_SPEED),
.reset_n(reset),
////// CPU INTERFACE ///////
.address(address_bus[3:1]),
.data_bus_in(Wishbone_driver_data_bus_write),
.data_bus_out(Wishbone_driver_data_bus_read),
.read_n(rd),
.write_n(wr),
.chip_select_n(wishbone_cs),
////// WISHBONE INTERFACE /////
.wb_ctrl_ack(wb_ctrl_ack),
.wb_ctrl_adr(wb_ctrl_adr),
.wb_ctrl_cyc(wb_ctrl_cyc),
.wb_ctrl_err(wb_ctrl_err),
.wb_ctrl_sel(wb_ctrl_sel),
.wb_ctrl_stb(wb_ctrl_stb),
.wb_ctrl_we(wb_ctrl_we),
.wb_ctrl_bte(wb_ctrl_bte),
.wb_ctrl_cti(wb_ctrl_cti),
.wb_ctrl_dat_r(wb_ctrl_dat_r),
.wb_ctrl_dat_w(wb_ctrl_dat_w)
);
wire [15:0] LITEDRAM_STATUS_REGISTER = { 13'd0, ddr3_pll_locked ,ddr3_init_error, ddr3_init_done };
wire [15:0] data_bus_read_DDR3;
Wishbone_memory_driver Wishbone_memory_driver(
///// GENERAL //////
.clock(CPU_SPEED),
.reset_n(reset),
////// CPU INTERFACE ///////
.address(address_bus),
.BHE(BHE),
.data_bus_in(data_bus_write),
.data_bus_out(data_bus_read_DDR3),
.wait_state(wait_state_WBIO),
.read_n(rd),
.write_n(wr),
.chip_select_n(!(DDR3_ram_cs&&ddr3_init_done)),
////// WISHBONE INTERFACE /////
.wb_mem_ack(wb_mem_ack),
.wb_mem_adr(wb_mem_adr),
.wb_mem_cyc(wb_mem_cyc),
.wb_mem_err(wb_mem_err),
.wb_mem_sel(wb_mem_sel),
.wb_mem_stb(wb_mem_stb),
.wb_mem_we(wb_mem_we),
.wb_mem_data_r(wb_mem_data_r),
.wb_mem_data_w(wb_mem_data_w)
);
wire wait_state;
assign wait_state=wait_state_WBIO||wait_state_I2C;
wire wait_state_WBIO;
wire wb_ctrl_ack;
wire [29:0] wb_ctrl_adr;
wire [1:0] wb_ctrl_bte;
wire [2:0] wb_ctrl_cti;
wire wb_ctrl_cyc;
wire [31:0] wb_ctrl_dat_r;
wire [31:0] wb_ctrl_dat_w;
wire wb_ctrl_err;
wire [3:0] wb_ctrl_sel;
wire wb_ctrl_stb;
wire wb_ctrl_we;
wire wb_mem_ack;
wire [24:0] wb_mem_adr;
wire wb_mem_cyc;
wire [31:0] wb_mem_data_r;
wire [31:0] wb_mem_data_w;
wire wb_mem_err;
wire [3:0] wb_mem_sel;
wire wb_mem_stb;
wire wb_mem_we;
litedram_core DDR3_RAM_DRIVER(
////// GENERAL ///////
.clk(clk48),
.user_clk(CPU_SPEED),
`ifdef SYNTHESIS
.rst(!reset),
.pll_locked(ddr3_pll_locked),
`else
.sim_trace(sim_trace),
`endif
////// DDR3 INTERFACE //////
`ifdef SYNTHESIS
.ddram_a(ddram_a[12:0]), //also ignored on the litedram core
.ddram_ba(ddram_ba),
.ddram_cas_n(ddram_cas_n),
.ddram_cke(ddram_cke),
.ddram_clk_n(1'b0), // goes nowhere ...
.ddram_clk_p(ddram_clk_p),
.ddram_cs_n(ddram_cs_n),
.ddram_dm(ddram_dm),
.ddram_dq(ddram_dq),
.ddram_dqs_n(2'b00), // goes nowhere ...
.ddram_dqs_p(ddram_dqs_p),
.ddram_odt(ddram_odt),
.ddram_ras_n(ddram_ras_n),
.ddram_reset_n(ddram_reset_n),
.ddram_we_n(ddram_we_n),
`endif
/////// SYSTEM MEMORY INTERFACE ////////////////
.init_done(ddr3_init_done),
.init_error(ddr3_init_error),
.user_port_wishbone_0_ack(wb_mem_ack),
.user_port_wishbone_0_adr(wb_mem_adr),
.user_port_wishbone_0_cyc(wb_mem_cyc),
.user_port_wishbone_0_dat_r(wb_mem_data_r),
.user_port_wishbone_0_dat_w(wb_mem_data_w),
.user_port_wishbone_0_err(wb_mem_err),
.user_port_wishbone_0_sel(wb_mem_sel),
.user_port_wishbone_0_stb(wb_mem_stb),
.user_port_wishbone_0_we(wb_mem_we),
.user_rst(user_rst),
/////// WISHBONE CONTROL INTERFACE ///////////
.wb_ctrl_ack(wb_ctrl_ack),
.wb_ctrl_adr(wb_ctrl_adr),
.wb_ctrl_cyc(wb_ctrl_cyc),
.wb_ctrl_err(wb_ctrl_err),
.wb_ctrl_sel(wb_ctrl_sel),
.wb_ctrl_stb(wb_ctrl_stb),
.wb_ctrl_we(wb_ctrl_we),
.wb_ctrl_bte(wb_ctrl_bte),
.wb_ctrl_cti(wb_ctrl_cti),
.wb_ctrl_dat_r(wb_ctrl_dat_r),
.wb_ctrl_dat_w(wb_ctrl_dat_w)
);
wire [15:0]CPU_I2C_data_bus_read;
wire i2c_cs;
wire [6:0] CPU_I2C_OUT_ADDRESS;
wire CPU_I2C_OUT_BUSY,CPU_I2C_OUT_TRANSACT,CPU_I2C_DIR;
wire [15:0]CPU_I2C_DATA_READ,CPU_I2C_DATA_WRITE;
wire CPU_I2C_IGN_ACK;
wire CPU_I2C_ERROR;
CPU_to_I2C_driver_bridge CPU_to_I2C_driver_bridge (
.clock(CPU_SPEED),
.reset_n(reset),
// CPU INTERFACE
.address(address_bus[2:0]),
.data_bus_in(data_bus_write),
.data_bus_out(CPU_I2C_data_bus_read),
.read_n(rd),
.write_n(wr),
.chip_select_n(i2c_cs),
// I2C DRIVER INTERFACE
.OUT_ADDRESS(CPU_I2C_OUT_ADDRESS),
.OUT_BUSY(CPU_I2C_OUT_BUSY),
.OUT_TRANSACT(CPU_I2C_OUT_TRANSACT),
.DIR(CPU_I2C_DIR),
.OUT_I2C_DATA_READ(CPU_I2C_DATA_READ),
.OUT_I2C_DATA_WRITE(CPU_I2C_DATA_WRITE),
.TRANS_WIDTH(CPU_I2C_TRANS_WIDTH),
.OUT_IGN_ACK(CPU_I2C_IGN_ACK),
.IN_ERROR(CPU_I2C_ERROR)
);
// Display driver
wire ascii_data_ready;
reg ascii_data_write_req=0;
reg [7:0] ascii_data;
ascii_to_HD44780_driver LCD_DRIVER(
/* system */
I2C_SPEED,
1'b1,
/* Data Input */
ascii_data_ready,
ascii_data_write_req,
ascii_data,
/* write circuitry */
!pcf_busy,
pcf_write_req,
pcf_data,
pcf_command_data
);
// Port expander driver
wire pcf_write_req,pcf_command_data,pcf_busy;
wire [3:0]pcf_data;
/* verilator lint_off UNUSEDSIGNAL */
wire [7:0]DISP_I2C_DATA_WRITE;
wire [15:0]DISP_I2C_DATA_READ;
/* verilator lint_on UNUSEDSIGNAL */
wire DISP_I2C_BUSY,DISP_I2C_TRANSACT;
wire [6:0] DISP_I2C_ADDRESS;
assign DISP_I2C_ADDRESS=7'h27;
wire DISP_DIR;
pcf8574_for_HD44780 PCF8574_driver(
.clock(I2C_SPEED),
.pcf_write_req(pcf_write_req),
.pcf_command_data(pcf_command_data),
.pcf_data(pcf_data),
.pcf_busy(pcf_busy),
.new_backlight(1'b0),
.backlight_update(1'b0),
.DIR(DISP_DIR),
.I2C_BUSY(DISP_I2C_BUSY),
.I2C_TRANSACT(DISP_I2C_TRANSACT),
.i2c_data_write(DISP_I2C_DATA_WRITE)
);
wire [6:0]MULT_TO_DRIV_I2C_ADDRESS;
wire MULT_TO_DRIV_I2C_BUSY;
wire MULT_TO_DRIV_I2C_TRANSACT;
wire [15:0]MULT_TO_DRIV_DATA_WRITE, MULT_TO_DRIV_DATA_READ;
wire MULT_TO_DRIV_DIR;
wire CPU_I2C_TRANS_WIDTH;
/* verilator lint_off UNUSEDSIGNAL */
wire DISP_ERROR; //TODO: It would be ideal to acknoledge any warnings but it's not really too important
/* verilator lint_on UNUSEDSIGNAL */
I2C_driver_multiplexer I2C_driver_multiplexer(
.clock(I2C_SPEED),
.reset_n(reset),
////// INPUT 1 ///////
.IN1_ADDRESS(DISP_I2C_ADDRESS),
.IN1_BUSY(DISP_I2C_BUSY),
.IN1_DIR(DISP_DIR),
.IN1_TRANSACT(DISP_I2C_TRANSACT),
.IN1_I2C_DATA_READ(DISP_I2C_DATA_READ),
.IN1_I2C_DATA_WRITE({8'h0,DISP_I2C_DATA_WRITE}),
.IN1_TRANS_WIDTH(1'b0),
.IN1_IGN_ACK(1'b0),
.IN1_ERROR(DISP_ERROR),
////// INPUT 2 ///////
.IN2_ADDRESS(CPU_I2C_OUT_ADDRESS),
.IN2_BUSY(CPU_I2C_OUT_BUSY),
.IN2_TRANSACT(CPU_I2C_OUT_TRANSACT),
.IN2_DIR(CPU_I2C_DIR),
.IN2_I2C_DATA_READ(CPU_I2C_DATA_READ),
.IN2_I2C_DATA_WRITE(CPU_I2C_DATA_WRITE),
.IN2_TRANS_WIDTH(CPU_I2C_TRANS_WIDTH),
.IN2_IGN_ACK(CPU_I2C_IGN_ACK),
.IN2_ERROR(CPU_I2C_ERROR),
////// OUTPUT ///////
.OUT_ADDRESS(MULT_TO_DRIV_I2C_ADDRESS),
.OUT_BUSY(MULT_TO_DRIV_I2C_BUSY),
.OUT_TRANSACT(MULT_TO_DRIV_I2C_TRANSACT),
.OUT_DIR(MULT_TO_DRIV_DIR),
.OUT_I2C_DATA_WRITE(MULT_TO_DRIV_DATA_WRITE),
.OUT_I2C_DATA_READ(MULT_TO_DRIV_DATA_READ),
.OUT_TRANS_WIDTH(MULT_TO_DRIV_TRANS_WIDTH),
.OUT_IGN_ACK(MULT_TO_DRIV_IGN_ACK),
.OUT_ERROR(MULT_TO_DRIV_ERROR)
);
// I2C driver
wire SDA_direction;
wire SCL,SDA_input,SDA_output;
wire MULT_TO_DRIV_TRANS_WIDTH;
wire MULT_TO_DRIV_IGN_ACK;
wire MULT_TO_DRIV_ERROR;
I2C_driver i2c_driver(
.clock(I2C_SPEED),
.SDA_input(SDA_input),
.SDA_output(SDA_output),
.SDA_direction(SDA_direction),
.SCL(SCL),
.address(MULT_TO_DRIV_I2C_ADDRESS),
.I2C_BUSY(MULT_TO_DRIV_I2C_BUSY),
.I2C_TRANSACT(MULT_TO_DRIV_I2C_TRANSACT),
.DIR(MULT_TO_DRIV_DIR),
.i2c_data_write(MULT_TO_DRIV_DATA_WRITE),
.i2c_data_read(MULT_TO_DRIV_DATA_READ),
.transact_width(MULT_TO_DRIV_TRANS_WIDTH),
.ignore_ack(MULT_TO_DRIV_IGN_ACK),
.error(MULT_TO_DRIV_ERROR)
);
`ifdef SYNTHESIS
TRELLIS_IO #(
// Parameters.
.DIR ("BIDIR")
) TRELLIS_IO_00 (
// pin
.B (i2c_sda),
//input
.I (1'd0),
//Direction
.T (~( SDA_direction & (~SDA_output) )),
// Output
.O (SDA_input)
);
assign i2c_scl=SCL;
`else
assign i2c_dir=SDA_direction;
assign i2c_scl=SCL;
assign SDA_input=i2c_sda_in;
assign i2c_sda_out=SDA_output;
`endif
endmodule

View File

@ -0,0 +1,257 @@
LOCATE COMP "clk48" SITE "A9";
IOBUF PORT "clk48" IO_TYPE=LVCMOS33;
FREQUENCY PORT "clk48" 48.0 MHz;
LOCATE COMP "ddram_a[0]" SITE "C4";
IOBUF PORT "ddram_a[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[1]" SITE "D2";
IOBUF PORT "ddram_a[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[2]" SITE "D3";
IOBUF PORT "ddram_a[2]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[2]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[3]" SITE "A3";
IOBUF PORT "ddram_a[3]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[3]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[4]" SITE "A4";
IOBUF PORT "ddram_a[4]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[4]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[5]" SITE "D4";
IOBUF PORT "ddram_a[5]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[5]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[6]" SITE "C3";
IOBUF PORT "ddram_a[6]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[6]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[7]" SITE "B2";
IOBUF PORT "ddram_a[7]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[7]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[8]" SITE "B1";
IOBUF PORT "ddram_a[8]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[8]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[9]" SITE "D1";
IOBUF PORT "ddram_a[9]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[9]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[10]" SITE "A7";
IOBUF PORT "ddram_a[10]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[10]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[11]" SITE "C2";
IOBUF PORT "ddram_a[11]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[11]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[12]" SITE "B6";
IOBUF PORT "ddram_a[12]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[12]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[13]" SITE "C1";
IOBUF PORT "ddram_a[13]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[13]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[14]" SITE "A2";
IOBUF PORT "ddram_a[14]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[14]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_a[15]" SITE "C7";
IOBUF PORT "ddram_a[15]" SLEWRATE=FAST;
IOBUF PORT "ddram_a[15]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_ba[0]" SITE "D6";
IOBUF PORT "ddram_ba[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_ba[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_ba[1]" SITE "B7";
IOBUF PORT "ddram_ba[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_ba[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_ba[2]" SITE "A6";
IOBUF PORT "ddram_ba[2]" SLEWRATE=FAST;
IOBUF PORT "ddram_ba[2]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_ras_n" SITE "C12";
IOBUF PORT "ddram_ras_n" SLEWRATE=FAST;
IOBUF PORT "ddram_ras_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_cas_n" SITE "D13";
IOBUF PORT "ddram_cas_n" SLEWRATE=FAST;
IOBUF PORT "ddram_cas_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_we_n" SITE "B12";
IOBUF PORT "ddram_we_n" SLEWRATE=FAST;
IOBUF PORT "ddram_we_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_cs_n" SITE "A12";
IOBUF PORT "ddram_cs_n" SLEWRATE=FAST;
IOBUF PORT "ddram_cs_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_dm[0]" SITE "D16";
IOBUF PORT "ddram_dm[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_dm[0]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_dm[1]" SITE "G16";
IOBUF PORT "ddram_dm[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_dm[1]" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_dq[0]" SITE "C17";
IOBUF PORT "ddram_dq[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[0]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[0]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[1]" SITE "D15";
IOBUF PORT "ddram_dq[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[1]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[1]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[2]" SITE "B17";
IOBUF PORT "ddram_dq[2]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[2]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[2]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[3]" SITE "C16";
IOBUF PORT "ddram_dq[3]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[3]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[3]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[4]" SITE "A15";
IOBUF PORT "ddram_dq[4]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[4]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[4]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[5]" SITE "B13";
IOBUF PORT "ddram_dq[5]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[5]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[5]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[6]" SITE "A17";
IOBUF PORT "ddram_dq[6]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[6]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[6]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[7]" SITE "A13";
IOBUF PORT "ddram_dq[7]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[7]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[7]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[8]" SITE "F17";
IOBUF PORT "ddram_dq[8]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[8]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[8]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[9]" SITE "F16";
IOBUF PORT "ddram_dq[9]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[9]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[9]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[10]" SITE "G15";
IOBUF PORT "ddram_dq[10]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[10]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[10]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[11]" SITE "F15";
IOBUF PORT "ddram_dq[11]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[11]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[11]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[12]" SITE "J16";
IOBUF PORT "ddram_dq[12]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[12]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[12]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[13]" SITE "C18";
IOBUF PORT "ddram_dq[13]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[13]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[13]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[14]" SITE "H16";
IOBUF PORT "ddram_dq[14]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[14]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[14]" TERMINATION=OFF;
LOCATE COMP "ddram_dq[15]" SITE "F18";
IOBUF PORT "ddram_dq[15]" SLEWRATE=FAST;
IOBUF PORT "ddram_dq[15]" IO_TYPE=SSTL135_I;
IOBUF PORT "ddram_dq[15]" TERMINATION=OFF;
LOCATE COMP "ddram_dqs_p[0]" SITE "B15";
IOBUF PORT "ddram_dqs_p[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_dqs_p[0]" IO_TYPE=SSTL135D_I;
IOBUF PORT "ddram_dqs_p[0]" TERMINATION=OFF;
IOBUF PORT "ddram_dqs_p[0]" DIFFRESISTOR=100;
LOCATE COMP "ddram_dqs_p[1]" SITE "G18";
IOBUF PORT "ddram_dqs_p[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_dqs_p[1]" IO_TYPE=SSTL135D_I;
IOBUF PORT "ddram_dqs_p[1]" TERMINATION=OFF;
IOBUF PORT "ddram_dqs_p[1]" DIFFRESISTOR=100;
LOCATE COMP "ddram_clk_p" SITE "J18";
IOBUF PORT "ddram_clk_p" SLEWRATE=FAST;
IOBUF PORT "ddram_clk_p" IO_TYPE=SSTL135D_I;
LOCATE COMP "ddram_cke" SITE "D18";
IOBUF PORT "ddram_cke" SLEWRATE=FAST;
IOBUF PORT "ddram_cke" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_odt" SITE "C13";
IOBUF PORT "ddram_odt" SLEWRATE=FAST;
IOBUF PORT "ddram_odt" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_reset_n" SITE "L18";
IOBUF PORT "ddram_reset_n" SLEWRATE=FAST;
IOBUF PORT "ddram_reset_n" IO_TYPE=SSTL135_I;
LOCATE COMP "ddram_vccio[0]" SITE "K16";
IOBUF PORT "ddram_vccio[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[0]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[1]" SITE "D17";
IOBUF PORT "ddram_vccio[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[1]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[2]" SITE "K15";
IOBUF PORT "ddram_vccio[2]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[2]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[3]" SITE "K17";
IOBUF PORT "ddram_vccio[3]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[3]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[4]" SITE "B18";
IOBUF PORT "ddram_vccio[4]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[4]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_vccio[5]" SITE "C6";
IOBUF PORT "ddram_vccio[5]" SLEWRATE=FAST;
IOBUF PORT "ddram_vccio[5]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_gnd[0]" SITE "L15";
IOBUF PORT "ddram_gnd[0]" SLEWRATE=FAST;
IOBUF PORT "ddram_gnd[0]" IO_TYPE=SSTL135_II;
LOCATE COMP "ddram_gnd[1]" SITE "L16";
IOBUF PORT "ddram_gnd[1]" SLEWRATE=FAST;
IOBUF PORT "ddram_gnd[1]" IO_TYPE=SSTL135_II;
LOCATE COMP "rgb_led0_r" SITE "K4";
IOBUF PORT "rgb_led0_r" IO_TYPE=LVCMOS33;
LOCATE COMP "rgb_led0_g" SITE "M3";
IOBUF PORT "rgb_led0_g" IO_TYPE=LVCMOS33;
LOCATE COMP "rgb_led0_b" SITE "J3";
IOBUF PORT "rgb_led0_b" IO_TYPE=LVCMOS33;
LOCATE COMP "gpio_0" SITE "N17";
IOBUF PORT "gpio_0" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_0" PULLMODE=DOWN;
LOCATE COMP "gpio_1" SITE "M18";
IOBUF PORT "gpio_1" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_1" PULLMODE=DOWN;
LOCATE COMP "gpio_5" SITE "B10";
IOBUF PORT "gpio_5" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_5" PULLMODE=DOWN;
LOCATE COMP "gpio_6" SITE "B9";
IOBUF PORT "gpio_6" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_6" PULLMODE=DOWN;
LOCATE COMP "gpio_9" SITE "C8";
IOBUF PORT "gpio_9" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_9" PULLMODE=DOWN;
LOCATE COMP "gpio_10" SITE "B8";
IOBUF PORT "gpio_10" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_10" PULLMODE=DOWN;
LOCATE COMP "gpio_11" SITE "A8";
IOBUF PORT "gpio_11" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_11" PULLMODE=DOWN;
LOCATE COMP "gpio_12" SITE "H2";
IOBUF PORT "gpio_12" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_12" PULLMODE=DOWN;
LOCATE COMP "gpio_13" SITE "J2";
IOBUF PORT "gpio_13" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_13" PULLMODE=DOWN;
LOCATE COMP "gpio_a0" SITE "L4";
IOBUF PORT "gpio_a0" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_a0" PULLMODE=DOWN;
LOCATE COMP "gpio_a1" SITE "N3";
IOBUF PORT "gpio_a1" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_a1" PULLMODE=DOWN;
LOCATE COMP "gpio_a2" SITE "N4";
IOBUF PORT "gpio_a2" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_a2" PULLMODE=DOWN;
LOCATE COMP "gpio_a3" SITE "H4";
IOBUF PORT "gpio_a3" IO_TYPE=LVCMOS33;
IOBUF PORT "gpio_a3" PULLMODE=DOWN;
LOCATE COMP "user_button" SITE "J17";
IOBUF PORT "user_button" IO_TYPE=SSTL135_I;
LOCATE COMP "reset_n" SITE "V17";
IOBUF PORT "reset_n" IO_TYPE=LVCMOS33;
LOCATE COMP "spiflash4x_cs_n" SITE "U17";
IOBUF PORT "spiflash4x_cs_n" IO_TYPE=LVCMOS33;
LOCATE COMP "spiflash4x_dq[0]" SITE "U18";
IOBUF PORT "spiflash4x_dq[0]" IO_TYPE=LVCMOS33;
LOCATE COMP "spiflash4x_dq[1]" SITE "T18";
IOBUF PORT "spiflash4x_dq[1]" IO_TYPE=LVCMOS33;
LOCATE COMP "spiflash4x_dq[2]" SITE "R18";
IOBUF PORT "spiflash4x_dq[2]" IO_TYPE=LVCMOS33;
LOCATE COMP "spiflash4x_dq[3]" SITE "N18";
IOBUF PORT "spiflash4x_dq[3]" IO_TYPE=LVCMOS33;
LOCATE COMP "usb_d_p" SITE "N1";
IOBUF PORT "usb_d_p" IO_TYPE=LVCMOS33;
LOCATE COMP "usb_d_n" SITE "M2";
IOBUF PORT "usb_d_n" IO_TYPE=LVCMOS33;
LOCATE COMP "usb_pullup" SITE "N2";
IOBUF PORT "usb_pullup" IO_TYPE=LVCMOS33;
LOCATE COMP "i2c_sda" SITE "C10";
IOBUF PORT "i2c_sda" IO_TYPE=LVCMOS33;
LOCATE COMP "i2c_scl" SITE "C9";
IOBUF PORT "i2c_scl" IO_TYPE=LVCMOS33;

View File

@ -0,0 +1,55 @@
#include "Vfpga_top.h"
#include "verilated.h"
#include "stdio.h"
Vfpga_top *system_state;
VerilatedContext* contextp;
/*In hz */
#define CPU_SPEED 1000
#define timeinc CPU_SPEED*1000000/2
void tick() {
system_state->clk48 = 1;
contextp->timeInc(timeinc);
system_state->eval();
system_state->clk48 = 0;
contextp->timeInc(timeinc);
system_state->eval();
}
int main(int argc, char** argv) {
contextp = new VerilatedContext;
// Set debug level, 0 is off, 9 is highest presently used
// May be overridden by commandArgs argument parsing
contextp->debug(0);
// Verilator must compute traced signals
contextp->traceEverOn(true);
contextp->commandArgs(argc, argv);
system_state = new Vfpga_top{contextp};
system_state->user_button=1;
system_state->i2c_sda_in=0;
//system_state->reset=1;
tick();
//system_state->reset=0;
tick();
tick();
//system_state->reset=1;
// Simulate until $finish
while(!contextp->gotFinish()){
tick();
}
system_state->final();
delete system_state;
delete contextp;
return 0;
}

View File

@ -0,0 +1,6 @@
`verilator_config
lint_off -rule COMBDLY -file "external_ip/litedram_core_ecp5_phy_sim.v"
lint_off -rule CASEINCOMPLETE -file "external_ip/litedram_core_ecp5_phy_sim.v"
lint_off -rule UNUSEDSIGNAL -file "external_ip/litedram_core_ecp5_phy_sim.v"
lint_off -rule WIDTHEXPAND -file "external_ip/litedram_core_ecp5_phy_sim.v"
lint_off -rule WIDTHTRUNC -file "external_ip/litedram_core_ecp5_phy_sim.v"

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -19,29 +19,56 @@
/* This warning is because we don't use the full address bus. */
/* verilator lint_off UNUSEDSIGNAL */
module doublemem(input [19:0] address,inout wire [15:0] data ,input rd,input wr,input BHE,input cs);
module doublemem
#(
parameter RAM_SIZE_IN_BYTES,
parameter ADDRESS_WIDTH=$clog2(RAM_SIZE_IN_BYTES)
)
( input [ ADDRESS_WIDTH-1 : 0 ] address,
output [15:0] cpu_read_data,
input [15:0] cpu_write_data,
input rd,
input wr,
input BHE,
input cs,
input clock
);
/* verilator lint_on UNUSEDSIGNAL */
reg [15:0] memory [0:32768];
reg [15:0] memory [0:(RAM_SIZE_IN_BYTES/2)-1];
initial begin
`ifndef YOSYS
string boot_code;
if(!$value$plusargs("BOOT_CODE=%s",boot_code))begin
$display("No boot code specified. Please add +BOOT_CODE=<path> to your vvp args");
$finish;
end
$readmemh(boot_code, memory,0,32767);
$readmemh(boot_code, memory,0,(RAM_SIZE_IN_BYTES/2)-1);
`else
//TODO: don't have it hard coded
$readmemh("../boot_code/i2c_bootloader.stxt", memory,0,(RAM_SIZE_IN_BYTES/2)-1); // 2KiB
`endif
end
assign data[7:0] = !address[0:0] & !rd & !cs ? memory[address[16:1]][15:8] : 8'hz;
assign data[15:8] = !BHE & !rd & !cs ? memory[address[16:1]][7:0] : 8'hz;
`ifdef USE_HIGH_IMPEDANCE
assign cpu_read_data[7:0] = !address[0:0] & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][15:8] : `16'hz;
assign cpu_read_data[15:8] = !BHE & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][ 7:0] : `16'hz;
`else
assign cpu_read_data[7:0] = memory[address[ADDRESS_WIDTH-1:1]][15:8];
assign cpu_read_data[15:8] = memory[address[ADDRESS_WIDTH-1:1]][ 7:0];
`endif
always @(negedge wr) begin
if(BHE==0)
memory[address[16:1]][7:0]<=data[15:8];
if(address[0]==0)
memory[address[16:1]][15:8]<=data[7:0];
always @(posedge clock) begin
if( cs == 0 && wr == 0) begin
if(BHE==0)
memory[address[ADDRESS_WIDTH-1:1]][7:0]<=cpu_write_data[15:8];
if(address[0]==0)
memory[address[ADDRESS_WIDTH-1:1]][15:8]<=cpu_write_data[7:0];
end
end
endmodule

View File

@ -0,0 +1,93 @@
/* CPU_to_I2C_driver_bridge - Implements CPU interface for the I2C_driver
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module CPU_to_I2C_driver_bridge (
input wire clock,
input wire reset_n,
// CPU INTERFACE
input wire [2:0] address,
input wire [15:0] data_bus_in,
output reg [15:0] data_bus_out,
input read_n,
input write_n,
input chip_select_n,
// I2C DRIVER INTERFACE
output wire [6:0] OUT_ADDRESS,
input wire OUT_BUSY,
output reg OUT_TRANSACT,
output reg DIR,
input wire [15:0] OUT_I2C_DATA_READ,
output reg [15:0] OUT_I2C_DATA_WRITE,
output reg TRANS_WIDTH,
output reg OUT_IGN_ACK,
input IN_ERROR
);
//assign data_bus_out=((address==3'h0)&&chip_select_n==1'b0&&read_n==1'b0)? 16'h0043 : 16'h0000;
//assign data_bus_out= (chip_select_n==1'b0&&read_n==1'b0) ? 16'h0043 : 16'h0000;
//assign data_bus_out= (1) ? 16'h0043 : 16'h0000;
reg [6:0] ADDRESS_REG=7'b1111111;
assign OUT_ADDRESS=ADDRESS_REG;
/* verilator lint_off UNUSEDSIGNAL */
reg [15:0]READ_DATA=16'h0;
/* verilator lint_on UNUSEDSIGNAL */
reg WAIT;
always @( posedge clock )begin
if ( reset_n==0 ) begin
WAIT<=0;
OUT_TRANSACT<=0;
end
if ( WAIT==1'b1 && OUT_BUSY==1'b1 )begin
WAIT<=1'b0;
OUT_TRANSACT<=0;
READ_DATA<=OUT_I2C_DATA_READ;
end
if ( chip_select_n==0 && read_n==0 )begin
case (address)
3'h0: data_bus_out <= {OUT_I2C_DATA_READ};
3'h2: data_bus_out <= {14'd0,IN_ERROR,OUT_BUSY|WAIT};
default: data_bus_out <= 16'h0;
endcase
end
if ( chip_select_n==0 && write_n==0 && address==3'd3 ) begin
OUT_TRANSACT<=1;
WAIT<=1;
end
if ( chip_select_n==0 && write_n==0 && address==3'd3 ) begin
DIR<=data_bus_in[8:8];
TRANS_WIDTH<=data_bus_in[9:9];
OUT_IGN_ACK<=data_bus_in[10:10];
end
if ( chip_select_n==0 && write_n==0 && address==3'd1 ) begin
ADDRESS_REG <= data_bus_in[14:8];
end
if ( chip_select_n==0 && write_n==0 && address==3'd2 ) begin
OUT_I2C_DATA_WRITE <= data_bus_in[15:0];
end
end
endmodule

View File

@ -0,0 +1,346 @@
/* I2C_driver.v - Implements an I2C interface
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module I2C_driver (
input wire clock,
input wire SDA_input,
output reg SDA_output,
output reg SDA_direction, //1:output 0:input
output reg SCL,
input wire [6:0] address,
output reg I2C_BUSY=0,
input wire I2C_TRANSACT,
input wire DIR,
input wire [15:0] i2c_data_write,
input wire transact_width, /* 0=byte 1=word */
/* verilator lint_off UNUSEDSIGNAL */
input wire ignore_ack,
/* verilator lint_on UNUSEDSIGNAL */
output reg [15:0] i2c_data_read=16'h4141,
output reg error=0
);
//assign i2c_data_read=16'h0042;
reg DIR_latched;
reg [5:0] i2c_state = 6'b100100;
reg [3:0] data_bit_counter;
reg [15:0] data_internal;
reg [6:0]address_internal;
reg trans_width_latch;
always @(posedge clock) begin
case (i2c_state)
/***** start sequence ******/
6'b000000:begin
SDA_direction<=1;
SDA_output<=1;
SCL<=1;
i2c_state<=6'b000001;
end
6'b000001:begin
SDA_output<=0;
SCL<=1;
i2c_state<=6'b000010;
end
6'b000010:begin
SDA_output<=0;
SCL<=0;
i2c_state<=6'b000011;
data_bit_counter<=0;
end
/****** Set address ********/
6'b000011:begin
SCL<=0;
i2c_state<=6'b000100;
end
6'b000100:begin
SCL<=0;
SDA_output<=address_internal[6:6];
address_internal[6:0]<={address_internal[5:0],1'b0};
data_bit_counter<=data_bit_counter+1;
i2c_state<=6'b000101;
end
6'b000101:begin
SCL<=1;
i2c_state<=6'b000110;
end
6'b000110:begin
SCL<=1;
if(data_bit_counter==4'd7)
i2c_state<=6'b000111;
else
i2c_state<=6'b000011;
end
/****** Read/Write *********/
6'b000111:begin
SCL<=0;
i2c_state<=6'b001000;
end
6'b001000:begin
SCL<=0;
SDA_output<=DIR_latched;/*Write=0 Read=1*/
i2c_state<=6'b001001;
end
6'b001001:begin
SCL<=1;
i2c_state<=6'b001010;
end
6'b001010:begin
SCL<=1;
i2c_state<=6'b001011;
end
/****** Acknowledge ********/
6'b001011:begin
SCL<=0;
SDA_direction<=0;
i2c_state<=6'b001100;
end
6'b001100:begin
SCL<=0;
i2c_state<=6'b001101;
end
6'b001101:begin
SCL<=1;
i2c_state<=6'b001110;
end
6'b001110:begin
SCL<=1;
if (SDA_input==1)begin
error<=1'b1;
i2c_state<=6'b100100;
end
i2c_state<=6'b001111;
data_bit_counter<=0;
end
/****** separator ********/
6'b001111:begin
SCL<=0;
SDA_output<=0;
i2c_state<=6'b010000;
end
6'b010000:begin
SCL<=0;
i2c_state<=6'b010001;
end
6'b010001:begin
SCL<=0;
SDA_output<=1;
i2c_state<=6'b010010;
end
6'b010010:begin
SCL<=0;
SDA_output<=1;
i2c_state<=6'b010011;
end
6'b010011:begin
SCL<=0;
SDA_output<=0;
i2c_state<=6'b010100;
end
/****** Send data ********/
6'b010100:begin
if(DIR_latched==1'b1)begin
SDA_direction<=0;
end else begin
SDA_direction<=1;
end
SCL<=0;
i2c_state<=6'b010101;
end
6'b010101:begin
SCL<=0;
if(DIR_latched==1'b0)begin
SDA_output<=data_internal[7:7];
data_internal[7:0]<={data_internal[6:0],1'b0};
end
data_bit_counter<=data_bit_counter+1;
i2c_state<=6'b010110;
end
6'b010110:begin
SCL<=1;
if(DIR_latched==1'b1)begin
i2c_data_read[15:0]<={8'h0,i2c_data_read[6:0],SDA_input};
end
i2c_state<=6'b010111;
end
6'b010111:begin
SCL<=1;
if(data_bit_counter==4'd8)begin
i2c_state<=6'b011000;
end else begin
i2c_state<=6'b010100;
end
end
/****** Acknowledge ********/
6'b011000:begin
// Note: If we read we want to send an ack,
// If we write we want to read an ack so it's reversed here
if(DIR_latched==1'b1)begin
SDA_direction<=1;
end else begin
SDA_direction<=0;
end
SCL<=0;
i2c_state<=6'b011001;
end
6'b011001:begin
SCL<=0;
if(DIR_latched==1'b1)begin
SDA_output<=1'b0;
end
i2c_state<=6'b011010;
end
6'b011010:begin
SCL<=1;
i2c_state<=6'b011011;
end
6'b011011:begin
SCL<=1;
if (SDA_input==1 && DIR_latched==1'b0)begin
error<=1'b1;
end
if(trans_width_latch==1'b1)begin
i2c_state<=6'b100101;
data_bit_counter<=4'd0;
end else
i2c_state<=6'b011100;
end
/****** Send data (16bit) ********/
6'b100101:begin
SCL<=0;
if(DIR_latched==1'b1)begin
SDA_direction<=0;
end else begin
SDA_direction<=1;
end
i2c_state<=6'b100110;
end
6'b100110:begin
SCL<=0;
if(DIR_latched==1'b0)begin
SDA_output<=data_internal[15:15];
data_internal[15:8]<={data_internal[14:8],1'b0};
end
data_bit_counter<=data_bit_counter+1;
i2c_state<=6'b100111;
end
6'b100111:begin
SCL<=1;
if(DIR_latched==1'b1)begin
i2c_data_read[15:0]<={i2c_data_read[14:8],SDA_input,i2c_data_read[7:0]};
end
i2c_state<=6'b101000;
end
6'b101000:begin
SCL<=1;
if(data_bit_counter==4'd8)begin
i2c_state<=6'b101001;
end else
i2c_state<=6'b100101;
end
/****** Acknowledge (16bit) ********/
6'b101001:begin
SDA_direction<=0;
SCL<=0;
i2c_state<=6'b101010;
end
6'b101010:begin
SCL<=0;
i2c_state<=6'b101011;
end
6'b101011:begin
SCL<=1;
i2c_state<=6'b101100;
end
6'b101100:begin
SCL<=1;
if ( SDA_input==1 && DIR_latched==1'b0 ) begin
error<=1'b1;
end
i2c_state<=6'b011100;
SDA_direction<=1;
end
/****** separator ********/
6'b011100:begin
SCL<=0;
SDA_output<=0;
i2c_state<=6'b011101;
end
6'b011101:begin
SCL<=0;
i2c_state<=6'b011110;
end
6'b011110:begin
SCL<=0;
SDA_output<=1;
i2c_state<=6'b011111;
end
6'b011111:begin
SCL<=0;
SDA_output<=1;
i2c_state<=6'b100000;
end
6'b100000:begin
SCL<=0;
SDA_output<=0;
i2c_state<=6'b100001;
end
/****** stop bit *******/
6'b100001:begin
SCL<=1;
SDA_output<=0;
i2c_state<=6'b100010;
end
6'b100010:begin
SCL<=1;
SDA_output<=1;
i2c_state<=6'b100011;
end
6'b100011:begin
SCL<=1;
SDA_output<=1;
i2c_state<=6'b100100;
I2C_BUSY<=0;
end
6'b100100:begin
if(I2C_TRANSACT==1)begin
I2C_BUSY<=1;
i2c_state<=0;
data_internal<=i2c_data_write;
address_internal<=address;
trans_width_latch<=transact_width;
DIR_latched<=DIR;
error<=1'b0;
end
end
default:begin
SCL<=0;
SDA_output<=0;
end
endcase
end
endmodule

View File

@ -0,0 +1,123 @@
/* I2C_driver_multiplexer.v - Implements a multiplexer for the SoC side of I2C_driver.v
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module I2C_driver_multiplexer (
input wire clock,
input wire reset_n,
////// INPUT 1 ///////
input wire [6:0] IN1_ADDRESS,
output reg IN1_BUSY,
input wire IN1_TRANSACT,
input wire IN1_DIR,
output reg [15:0] IN1_I2C_DATA_READ,
input wire [15:0] IN1_I2C_DATA_WRITE,
input IN1_TRANS_WIDTH,
input IN1_IGN_ACK,
output reg IN1_ERROR,
////// INPUT 2 ///////
input wire [6:0] IN2_ADDRESS,
output reg IN2_BUSY,
input wire IN2_TRANSACT,
input wire IN2_DIR,
output reg [15:0] IN2_I2C_DATA_READ,
input wire [15:0] IN2_I2C_DATA_WRITE,
input IN2_TRANS_WIDTH,
input IN2_IGN_ACK,
output reg IN2_ERROR,
////// OUTPUT ///////
output wire [6:0] OUT_ADDRESS,
input wire OUT_BUSY,
output reg OUT_TRANSACT,
output wire OUT_DIR,
input wire [15:0] OUT_I2C_DATA_READ,
output wire [15:0] OUT_I2C_DATA_WRITE,
output OUT_TRANS_WIDTH,
output wire OUT_IGN_ACK,
input wire OUT_ERROR
);
reg select;
assign OUT_TRANS_WIDTH = select ? IN1_TRANS_WIDTH : IN2_TRANS_WIDTH;
assign OUT_I2C_DATA_WRITE = select ? IN1_I2C_DATA_WRITE : IN2_I2C_DATA_WRITE;
assign OUT_ADDRESS = select ? IN1_ADDRESS : IN2_ADDRESS;
assign OUT_IGN_ACK = select ? IN1_IGN_ACK : IN2_IGN_ACK;
assign OUT_DIR= select ? IN1_DIR : IN2_DIR;
reg [1:0] STATE;
reg SERVICED;
always @(posedge clock)begin
if(reset_n==1'b0)begin
OUT_TRANSACT<=0;
IN1_BUSY<=0;
IN2_BUSY<=0;
STATE<=2'd0;
end else begin
case(STATE)
2'd0:begin
if(IN1_TRANSACT&&OUT_BUSY==1'b0)begin
select<=1'b1;
OUT_TRANSACT<=1;
STATE<=2'd1;
SERVICED<=1'b0;
end else if(IN2_TRANSACT&&OUT_BUSY==1'b0)begin
select<=1'b0;
OUT_TRANSACT<=1;
IN1_BUSY<=1;
STATE<=2'd1;
SERVICED<=1'b1;
end
if(OUT_BUSY==1'b0)begin
IN1_BUSY<=0;
IN2_BUSY<=0;
end
end
2'd1:begin
if(OUT_BUSY==1'b1)begin
STATE<=2'd0;
OUT_TRANSACT<=0;
end
if(SERVICED==1'b0)begin
IN1_BUSY<=1;
end else begin
IN2_BUSY<=1;
end
end
default:begin
STATE<=2'b0;
end
endcase
end
end
always @(negedge OUT_BUSY)begin
if(select)begin
IN1_I2C_DATA_READ<=OUT_I2C_DATA_READ;
IN1_ERROR<=OUT_ERROR;
end else begin
IN2_I2C_DATA_READ<=OUT_I2C_DATA_READ;
IN2_ERROR<=OUT_ERROR;
end
end
endmodule

View File

@ -0,0 +1,127 @@
/* Wishbone_driver.v - Implements a classic wishbone master
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module Wishbone_IO_driver (
input wire clock,
input wire reset_n,
input wire [2:0] address,
input wire [15:0] data_bus_in,
output reg [15:0] data_bus_out,
input read_n,
input write_n,
input chip_select_n,
input wire wb_ctrl_ack,
output wire [29:0] wb_ctrl_adr,
output wire [1:0] wb_ctrl_bte,
output wire [2:0] wb_ctrl_cti,
output wire wb_ctrl_cyc,
input wire [31:0] wb_ctrl_dat_r,
output wire [31:0] wb_ctrl_dat_w,
input wire wb_ctrl_err,
output wire [3:0] wb_ctrl_sel,
output wire wb_ctrl_stb,
output wire wb_ctrl_we
);
reg [13:0]WISHBONE_ADDR=14'd0;
reg WISHBONE_ACTIVE_CYCLE=1'b0;
wire WISHBONE_ERROR_IN;
reg [3:0]WISHBONE_SELECT=4'd0;
reg WISHBONE_VALID_TRANSFER=1'b0;
reg WISHBONE_WRITE=1'b1;
wire WISHBONE_ACK_IN;
reg [31:0]WISHBONE_DATA_READ=32'd0;
wire [31:0]WISHBONE_DATA_WRITE;
assign WISHBONE_ACK_IN=wb_ctrl_ack;
assign wb_ctrl_adr={16'd0,WISHBONE_ADDR};
assign WISHBONE_ERROR_IN=wb_ctrl_err;
assign wb_ctrl_sel=WISHBONE_SELECT;
assign wb_ctrl_stb=WISHBONE_VALID_TRANSFER;
assign wb_ctrl_cyc=WISHBONE_ACTIVE_CYCLE;
assign wb_ctrl_we=WISHBONE_WRITE;
assign wb_ctrl_bte=2'b00; // Burst Type Extension 00:Linear burst
assign wb_ctrl_cti=3'b000; // Cycle Type Idenfier 000:Classic cycle
assign WISHBONE_DATA_WRITE=wb_ctrl_dat_r;
assign wb_ctrl_dat_w=WISHBONE_DATA_READ;
reg [31:0]WISHBONE_READ_BUFFER;
reg [1:0]just_transacted;
reg [1:0]WISHBONE_STATUS;
wire CYCLE_END=(WISHBONE_ACK_IN==1'b1);//||WISHBONE_ERROR_IN==1'b1);
always @( posedge clock )begin
if(reset_n==0)begin
just_transacted<=2'b0;
end
if(just_transacted==2'd1&&CYCLE_END==1'b1)begin
WISHBONE_READ_BUFFER<=WISHBONE_DATA_WRITE;
end
if(chip_select_n==0 && write_n==0 )begin
case (address)
3'h0: WISHBONE_DATA_READ[15:0] <=data_bus_in;
3'h1: WISHBONE_DATA_READ[31:16]<=data_bus_in;
3'h2: WISHBONE_ADDR[13:0]<=data_bus_in[13:0];
3'h3: begin end
default: begin end
endcase
case (address)
3'h3: begin
WISHBONE_ACTIVE_CYCLE<=1;
WISHBONE_VALID_TRANSFER<=1;
WISHBONE_SELECT<=4'hF;
end
default: begin end
endcase
if(address==3'h3)begin
WISHBONE_WRITE<=1'b1;//data_bus_in[0:0];
if(data_bus_in[0:0]==1'b1)begin //write req
just_transacted<=2'd2;
end else begin
just_transacted<=2'd1;
end
end
end else if(just_transacted!=2'd0&&CYCLE_END==1'b1)begin // In the unlikely scenario that the CPU wants to write without having checked for the previous write
WISHBONE_STATUS[0:0]<=WISHBONE_ACK_IN;
WISHBONE_STATUS[1:1]<=WISHBONE_ERROR_IN;
WISHBONE_ACTIVE_CYCLE<=0;
WISHBONE_VALID_TRANSFER<=0;
just_transacted<=2'b0;
end
if ( chip_select_n==0 && read_n==0 )begin
case (address)
/* verilator lint_off BLKSEQ */
/* Makes icarus verilog work as expected, not too sure if it helps real hardware yet*/
3'h0: data_bus_out = WISHBONE_READ_BUFFER[15:0];
3'h1: data_bus_out = WISHBONE_READ_BUFFER[31:16];
3'h2: data_bus_out = {13'd0,WISHBONE_STATUS,just_transacted==2'd0||CYCLE_END==1'b1}; //1:NOT BUSY 0:BUSY
default: data_bus_out = 16'h0;
/* verilator lint_on BLKSEQ */
endcase
end
end
endmodule

View File

@ -0,0 +1,73 @@
/* Wishbone_driver.v - Implements a classic wishbone master that maps directly in memory space
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module Wishbone_memory_driver (
input wire clock,
/* verilator lint_off UNUSEDSIGNAL */
input wire reset_n,
/* verilator lint_on UNUSEDSIGNAL */
input wire [19:0] address,
input wire [15:0] data_bus_in,
output reg [15:0] data_bus_out,
output wire wait_state,
input read_n,
input write_n,
input chip_select_n,
input BHE,
input wire wb_mem_ack,
output wire [24:0] wb_mem_adr,
output reg wb_mem_cyc,
/* verilator lint_off UNUSEDSIGNAL */
// I don't yet use the upper word
input wire [31:0] wb_mem_data_r,
/* verilator lint_on UNUSEDSIGNAL */
output wire [31:0] wb_mem_data_w,
/* verilator lint_off UNUSEDSIGNAL */
input wire wb_mem_err,
/* verilator lint_on UNUSEDSIGNAL */
output wire [3:0] wb_mem_sel,
output reg wb_mem_stb,
output wire wb_mem_we
);
assign wb_mem_adr={6'd0,address[19:1]};
assign wb_mem_sel={2'b11,!BHE,!address[0]};
always @(posedge clock)begin
wb_mem_cyc<=( (!read_n||!write_n)^(wb_mem_ack) )&(!chip_select_n);
wb_mem_stb<=( (!read_n||!write_n)^(wb_mem_ack) )&(!chip_select_n);
end
always @(posedge wb_mem_ack)begin
data_bus_out<=wb_mem_data_r[15:0];
end
assign wb_mem_data_w={16'd0,data_bus_in};
assign wait_state=( (!read_n||!write_n)^(wb_mem_ack) )&(!chip_select_n);
assign wb_mem_we=read_n;
endmodule

View File

@ -0,0 +1,348 @@
/* ascii_to_HD44780_driver.v - driver that takes in ascii and outputs control
sequences for an HD44780 display
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module ascii_to_HD44780_driver (
/* system */
input wire clock,
input wire rst_n,
/* Data Input */
output reg in_data_ready=0,
input data_write_req,
input [7:0] in_ascii_data,
/* write circuitry */
input wire done_writing,
output reg write_req=0,
output reg [3:0] data,
output reg cmd_data=0
);
initial begin
init_cmd_data[ 0] = 4'h3;
init_cmd_data[ 1] = 4'h3;
init_cmd_data[ 2] = 4'h3;
init_cmd_data[ 3] = 4'h2;
init_cmd_data[ 4] = 4'h2; //0x28
init_cmd_data[ 5] = 4'h8;
init_cmd_data[ 6] = 4'h0; //0x07
init_cmd_data[ 7] = 4'h7;
init_cmd_data[ 8] = 4'h0; //0x0F
init_cmd_data[ 9] = 4'hF;
init_cmd_data[10] = 4'h0; //0x01
init_cmd_data[11] = 4'h1;
init_cmd_data[12] = 4'h0; //0x06
init_cmd_data[13] = 4'h6;
init_cmd_data[14] = 4'h0; // 0x02
init_cmd_data[15] = 4'h2;
end
reg [4:0] init_seq=0;
reg [3:0] init_cmd_data [15:0];
reg [7:0]print_data;
reg [1:0]line=0;
reg [5:0]col=0;
reg [7:0] driver_state =0;
reg next_line;
reg [7:0]clear_count;
always @(posedge clock) begin
if(rst_n==0)begin
in_data_ready<=0;
write_req<=1'b0;
init_seq<=5'd0;
cmd_data<=1'b0;
line<=0;
col<=0;
driver_state<=0;
end else begin
case(driver_state)
8'd0:begin
if(init_seq!=5'd16)begin
/** Initialise display **/
data<=init_cmd_data[init_seq[3:0]];
cmd_data<=1'b0;
in_data_ready<=0;
if(!done_writing)begin
init_seq<=init_seq+5'd1;
driver_state<=8'd12;
write_req<=1'b0;
end else begin
write_req<=1'b1;
end
end else if(col==6'd20)begin
/** Check if we run out of screen **/
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=1;
end else if(data_write_req==1)begin
if(in_ascii_data==8'h0A)begin // '\n'
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=1;
end else if(in_ascii_data==8'h0D)begin // '\r'
driver_state<=8'd6;
cmd_data<=1'b0;
next_line<=0;
end else if(in_ascii_data==8'h1b)begin // '\e'
driver_state<=8'd13;
cmd_data<=1'b1;
in_data_ready<=0;
end else begin
if (in_ascii_data[7:5]==3'b000||in_ascii_data[7:7]==1'b1)
if(in_ascii_data==8'h00)
print_data<=8'h23;
else
print_data<=8'h3F;
else
print_data<=in_ascii_data;
cmd_data<=1'b1;
driver_state<=8'd9;
end
in_data_ready<=0;
end else begin
in_data_ready<=1;
end
end
8'd6:begin
if(next_line)begin
case(line)
2'd0: data<=4'hC;
2'd1: data<=4'h9;
2'd2: data<=4'hD;
2'd3: data<=4'hD;
endcase
end else begin
case(line)
2'd0: data<=4'h8;
2'd1: data<=4'hC;
2'd2: data<=4'h9;
2'd3: data<=4'hD;
endcase
end
if(done_writing==0)begin
driver_state<=8'd7;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd7:begin
if(done_writing==1)
driver_state<=8'd8;
end
8'd8:begin
if(next_line)begin
case(line)
2'd0: begin data<=4'h0; end
2'd1: begin data<=4'h4; end
2'd2: begin data<=4'h4; end
2'd3: begin data<=4'h4; end
endcase
end else begin
case(line)
2'd0: begin data<=4'h0; end
2'd1: begin data<=4'h0; end
2'd2: begin data<=4'h4; end
2'd3: begin data<=4'h4; end
endcase
end
if(!done_writing)begin
driver_state<=8'd12;
col<=0;
write_req<=1'b0;
if(next_line)begin
case(line)
2'd0: begin line<=1; end
2'd1: begin line<=2; end
2'd2: begin line<=3; end
2'd3: begin line<=3; end
endcase
end
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd9:begin
data<=print_data[7:4];
if(!done_writing)begin
driver_state<=8'd10;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd10:begin
if(done_writing==1)
driver_state<=8'd11;
end
8'd11:begin
data<=print_data[3:0];
if(!done_writing)begin
driver_state<=8'd12;
write_req<=1'b0;
col<=col+1;
end else
write_req<=1'b1;
end
8'd12:begin
if(done_writing)
driver_state<=8'd0;
end
8'd13:begin // Escape sequence start
if(data_write_req==1'b0)begin
driver_state<=8'd14;
in_data_ready<=1;
end
end
8'd14:begin
if(data_write_req==1'b1)begin
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h5b:begin// '['
driver_state<=8'd16;
end
default:begin
driver_state<=8'd15;
end
endcase
end
end
8'd15:begin
if(data_write_req==1'b0)begin
driver_state<=8'd0;
end
end
8'd16:begin // Second part of escape sequency
if(data_write_req==1'b0)begin
in_data_ready<=1'b1;
driver_state<=8'd17;
end
end
8'd17:begin
if(data_write_req==1'b1)begin
driver_state<=8'd17;
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h48:begin// 'H'
driver_state<=8'd25;
cmd_data<=1'b0;
clear_count<=8'd80;
end
8'h32:begin// '2'
driver_state<=8'd23;
end
default: begin
driver_state<=8'd15;
end
endcase
end
end
8'd18:begin
data<=4'h2;
if(!done_writing)begin
driver_state<=8'd19;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd19:begin
if(done_writing==1)
driver_state<=8'd20;
end
8'd20:begin
data<=4'h0;
if(!done_writing)begin
driver_state<=8'd21;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd21:begin
if(done_writing)begin
driver_state<=8'd22;
clear_count<=clear_count-8'd1;
end
end
8'd22:begin
if(clear_count==8'd0)begin
driver_state<=8'd0;
end else begin
driver_state<=8'd18;
end
end
8'd23:begin
if(data_write_req==1'b0)begin
in_data_ready<=1'b1;
driver_state<=8'd24;
end
end
8'd24:begin
if(data_write_req==1'b1)begin
driver_state<=8'd17;
in_data_ready<=1'b0;
case(in_ascii_data[7:0])
8'h4a:begin// 'J'
driver_state<=8'd18;
clear_count<=8'd80;
end
default:begin
driver_state<=8'd0;
end
endcase
end
end
8'd25:begin
data<=4'h8;
if(!done_writing)begin
driver_state<=8'd26;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd26:begin
if(done_writing==1)
driver_state<=8'd27;
end
8'd27:begin
data<=4'h0;
if(!done_writing)begin
driver_state<=8'd28;
write_req<=1'b0;
end else
write_req<=1'b1;
end
8'd28:begin
if(done_writing)begin
driver_state<=8'd0;
col<=0;
line<=0;
end
end
default: begin driver_state<=0; end
endcase
end
end
endmodule

View File

@ -0,0 +1,126 @@
/* pcf8574_for_HD44780.v - takes in control sequences for an HD44780 display
and outputs data that control a pcf8574 connected to a HD44780 in a standard
manner over i2c
This file is part of the 9086 project.
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
module pcf8574_for_HD44780(
input wire clock,
input wire pcf_write_req,
input wire pcf_command_data,
input wire [3:0]pcf_data,
output reg pcf_busy=0,
/* verilator lint_off UNUSEDSIGNAL */
input new_backlight,
/* verilator lint_on UNUSEDSIGNAL */
input backlight_update,
input I2C_BUSY,
output reg I2C_TRANSACT=0,
output reg DIR=0,
output reg [7:0]i2c_data_write
);
reg backlight=1;
reg backlight_latch=0;
reg [3:0]pcf_state=0;
always @(posedge clock) begin
// [ D7 , D6 , D5 , D4 , BACKLIGHT , EN , WRITE , COMMAND/DATA ]
if(backlight_update)
backlight_latch<=1;
case(pcf_state)
4'b0000: begin /*Idle*/
if(pcf_write_req&&I2C_BUSY==0)begin
pcf_state<=4'b0001;
I2C_TRANSACT<=0;
pcf_busy<=1;
end else if(backlight_latch&&I2C_BUSY==0)begin
pcf_state<=4'b1111;
I2C_TRANSACT<=0;
pcf_busy<=1;
end
end
4'b0001: begin
if(I2C_BUSY==0)begin
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
I2C_TRANSACT<=1;
backlight_latch<=0;
pcf_state<=4'b0010;
end
end
4'b0010:begin
if(I2C_BUSY==1)begin
I2C_TRANSACT<=0;
pcf_state<=4'b0011;
end
end
4'b0011: begin
if(I2C_BUSY==0)begin
i2c_data_write<={pcf_data[3:0],backlight,1'b1,1'b0,pcf_command_data};
I2C_TRANSACT<=1;
backlight_latch<=0;
pcf_state<=4'b0100;
end
end
4'b0100:begin
if(I2C_BUSY==1)begin
I2C_TRANSACT<=0;
pcf_state<=4'b0101;
end
end
4'b0101: begin
if(I2C_BUSY==0)begin
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
I2C_TRANSACT<=1;
pcf_state<=4'b0110;
end
end
4'b0110: begin
if(I2C_BUSY==1)begin
I2C_TRANSACT<=0;
pcf_state<=4'b0111;
end
end
4'b0111:begin
if(I2C_BUSY==0)begin
pcf_state<=4'b0000;
pcf_busy<=1'b0;
end
end
4'b1111:begin
if(I2C_BUSY==1)begin
pcf_state<=4'b0000;
I2C_TRANSACT<=1'b0;
pcf_busy<=1'b0;
end else begin
i2c_data_write<={4'b0,backlight,1'b0,1'b0,1'b0};
backlight_latch<=0;
I2C_TRANSACT<=1'b1;
pcf_busy<=1'b1;
end
end
default:begin
pcf_state<=0;
end
endcase
end
endmodule

View File

@ -1,63 +0,0 @@
/* proc_state_def.v - Definitions of the states in the main state machine
of the 9086 CPU.
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`define PROC_STATE_BITS 6
`define PROC_HALT_STATE 6'b000000
/*INSTRUCTION FETCH STATE*/
`define PROC_IF_STATE_ENTRY 6'b000001
`define PROC_IF_WRITE_CIR 6'b000010
`define PROC_IF_STATE_EXTRA_FETCH_SET 6'b000011
`define PROC_IF_STATE_EXTRA_FETCH 6'b000100
/*DECODE SATE*/
`define PROC_DE_STATE_ENTRY 6'b001000
`define PROC_DE_LOAD_16_PARAM 6'b001001
`define PROC_DE_LOAD_16_EXTRA_FETCH_SET 6'b001010
`define PROC_DE_LOAD_16_EXTRA_FETCH 6'b001011
`define PROC_DE_LOAD_REG_TO_PARAM 6'b001100
/*MEM/IO READ*/
`define PROC_MEMIO_READ 6'b010000
`define PROC_MEMIO_READ_SETADDR 6'b010001
`define PROC_MEMIO_GET_ALIGNED_DATA 6'b010010 /* :) */
`define PROC_MEMIO_GET_UNALIGNED_DATA 6'b010011 /* :( */
`define PROC_MEMIO_GET_SECOND_BYTE 6'b010100
`define PROC_MEMIO_GET_SECOND_BYTE1 6'b010101
`define PROC_DE_LOAD_8_PARAM 6'b010110
/*EXECUTE STATE*/
`define PROC_EX_STATE_ENTRY 6'b100000
/*MEM/IO WRITE*/
`define PROC_MEMIO_WRITE 6'b101000
`define PROC_MEMIO_PUT_ALIGNED_16BIT_DATA 6'b101001
`define PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA 6'b101010
`define PROC_MEMIO_PUT_BYTE 6'b101011
`define PROC_MEMIO_WRITE_EXIT 6'b101101
`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT 6'b101111
`define PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2 6'b110010
`define PROC_NEXT_MICROCODE 6'b111000
`define PROC_RESET 6'b111100

View File

@ -1,8 +1,8 @@
/* processor.v - implementation of most functions of the 9086 processor
/* processor.v - Connects the different modules comprising the processor
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -17,616 +17,189 @@
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`include "proc_state_def.v"
`include "exec_state_def.v"
`include "alu_header.v"
`include "config.v"
`include "ucode_header.v"
`include "error_header.v"
//HALT: active high
//ERROR: active high
//IOMEM: 1=IO 0=MEM
//BHE: active low
//write: active low
//read: active low
//reset: active low
module processor ( input clock, input reset, output reg [19:0] external_address_bus, inout [15:0] external_data_bus,output reg read, output reg write,output reg BHE,output reg IOMEM, output reg HALT,output reg ERROR);
module processor (
/*if we don't read, output the register to have the bus stable by the write falling edge*/
reg [15:0] data_bus_output_register;
assign external_data_bus=read?data_bus_output_register:16'hz;
/* MISC */ input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR
/* MEMORY / IO */ ,output [19:0] external_address_bus, input [15:0] external_data_bus_read, output [15:0] external_data_bus_write, input wait_state, output read, output write,output BHE,output IOMEM
/*** Global Definitions ***/
`ifdef CALCULATE_IPC
/* STATISTICS */ ,output wire new_instruction
`endif
`ifdef OUTPUT_JSON_STATISTICS
/* */ ,output wire [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT, output wire VALID_INSTRUCTION_STAT, output wire jump_req_debug
`endif
);
`ifdef OUTPUT_JSON_STATISTICS
assign jump_req_debug=biu_jump_req;
`endif
/* If there is an error either from the decoder or execution unit set it to ERROR */
assign ERROR=(DE_ERROR!=`ERR_NO_ERROR)?DE_ERROR:(EXEC_ERROR!=`ERR_NO_ERROR)?EXEC_ERROR:`ERR_NO_ERROR;
/*############ Execution Unit ################################################### */
wire [`ERROR_BITS-1:0] EXEC_ERROR;
wire biu_read_request,biu_jump_req,biu_write_request,use_exec_reg_addr;
wire [3:0] EXEC_reg_read_port1_addr;
wire [15:0] ALU_O;
wire [7:0] EX2DE_FLAGS;
wire [15:0] BIU_ADDRESS_INPUT;
wire reg_write_we;
wire next_exec;
execute_unit execute_unit (
/***************** GENERAL *****************/
/* */ clock, reset, write, EXEC_ERROR
/*************** INPUT FROM DE ***************/
/* SYNC SIGNALS */ ,valid_exec_data,set_initial_values
/* INSTR. PARAMS */ ,Wbit, IN_MOD, OUT_MOD, RM
/* DATA */ ,PARAM1_INIT,PARAM2_INIT,ProgCount
/* STATE CONTROL */ ,next_state
/* ALU CONTROL */ ,in_alu_sel1, in_alu_sel2, ALU_OP, ALU_O
/* OTHER */ ,memio_address_select
/**************** OUTPUT TO DE ****************/
/* SYNC SIGNALS */ ,next_exec
/* FLAGS */ ,EX2DE_FLAGS
/**************** OUTPUT TO BIU ****************/
/* */ ,BIU_ADDRESS_INPUT
/* */ ,biu_read_request, biu_jump_req, biu_write_request
/*************** INPUT FROM BIU ****************/
/* */ ,BIU_VALID_DATA,BIU_EX_DATA_READ
/**************** OUTPUT TO BIU ****************/
/* */ ,BIU_EX_DATA_WRITE
/***************** REGISTERS *****************/
/* */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr
/* */ ,use_exec_reg_addr, reg_write_we
);
/*############ Bus Interface Unit ############################################### */
wire [15:0] INSTRUCTION_LOCATION;
wire [15:0] BIU_EX_DATA_READ,BIU_EX_DATA_WRITE;
wire [31:0] IF2DE_INSTRUCTION;
wire BIU_VALID_DATA;
wire VALID_INSTRUCTION;
BIU BIU(
/***************** GENERAL *****************/
/* */ clock,reset
/**************** OUTSIDE WORLD ****************/
/* */ ,external_address_bus
/* */ ,external_data_bus_read,external_data_bus_write,read,write,BHE,IOMEM
/* */ ,wait_state
/**************** OUTPUT TO DE ****************/
/* */ ,IF2DE_INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION
/* */ ,BIU_VALID_DATA
/**************** INPUT FROM DE ****************/
,Wbit,MEM_OR_IO,VALID_INSTRUCTION_ACK
/**************** INPUT FROM EX ****************/
/* */ ,biu_jump_req,biu_write_request,biu_read_request
/* */ ,BIU_ADDRESS_INPUT,BIU_EX_DATA_WRITE
/***************** OUTPUT TO EX ****************/
/* */ ,BIU_EX_DATA_READ
`ifdef OUTPUT_JSON_STATISTICS
/***************** STATISTICS *****************/
/* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT
`endif
);
reg [`PROC_STATE_BITS-1:0] state;
/*############ Decoder ########################################################## */
wire Wbit, Sbit, opcode_size;
wire [`PROC_STATE_BITS-1:0] next_state;
wire [2:0]RM;
wire [15:0]DE_PARAM1;// Input param1 form decoder to alu
wire [15:0]DE_PARAM2;
wire DE_ERROR,DE_HALT;
wire [3:0]DE_reg_read_port1_addr,DE_reg_write_addr,DE_reg_read_port2_addr;
wire [11:0]DE_REGISTER_CONTROL;
wire [2:0]INSTRUCTION_INFO;
wire [1:0]DECODER_SIGNALS;
wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry;
reg SIMPLE_MICRO; /* output simple decodings (=0) or microcode data (=1) */
wire [2:0] DE_instruction_size;
reg instruction_size_init;
wire [2:0] instruction_size;
assign instruction_size = instruction_size_init ? 3'b010 : DE_instruction_size;
wire memio_address_select;
wire MEM_OR_IO;
wire [`ERROR_BITS-1:0] DE_ERROR;
wire valid_exec_data, set_initial_values, Wbit;
wire memio_address_select, MEM_OR_IO, VALID_INSTRUCTION_ACK;
wire [1:0] in_alu_sel1, in_alu_sel2;
wire [2:0] IN_MOD,OUT_MOD, RM;
wire [3:0] DE_reg_read_port1_addr,DE_reg_read_port2_addr, reg_write_addr;
wire [15:0] PARAM1_INIT, PARAM2_INIT, ProgCount;
wire [`ALU_OP_BITS-1:0] ALU_OP;
wire [`EXEC_STATE_BITS-1:0] next_state;
decoder decoder(
.CIR(CIR),
.FLAGS(FLAGS),
.INSTRUCTION_INFO(INSTRUCTION_INFO),
.DECODER_SIGNALS(DECODER_SIGNALS),
.next_state(next_state),
.IN_MOD(IN_MOD),
.RM(RM),
.PARAM1(DE_PARAM1),
.PARAM2(DE_PARAM2),
.in_alu1_sel1(in_alu1_sel1),
.in_alu1_sel2(in_alu1_sel2),
.OUT_MOD(OUT_MOD),
.REGISTER_FILE_CONTROL(DE_REGISTER_CONTROL),
.ALU_1OP(ALU_1OP),
.seq_addr_entry(ucode_seq_addr_entry),
.SIMPLE_MICRO(SIMPLE_MICRO),
.seq_addr_input(ucode_seq_addr),
.instruction_size(DE_instruction_size),
.memio_address_select(memio_address_select),
.MEM_OR_IO(MEM_OR_IO)
/***************** GENERAL *****************/
/* Input from sys. */ clock, reset
/* Output to sys. */ ,MEM_OR_IO, DE_ERROR, HALT
/*************** INPUT FROM IF ***************/
/* */ ,IF2DE_INSTRUCTION, VALID_INSTRUCTION
/* */ ,INSTRUCTION_LOCATION
/*************** OUTPUT TO IF ***************/
/* */ ,VALID_INSTRUCTION_ACK
/*************** INPUT FROM EX ***************/
/* */ ,EX2DE_FLAGS[7:0], next_exec
/*************** OUTPUT TO DE ***************/
/* SYNC SIGNALS */ ,set_initial_values, valid_exec_data
/* INSTR. PARAMS */ ,Wbit, IN_MOD, OUT_MOD, RM
/* DATA */ ,PARAM1_INIT, PARAM2_INIT, ProgCount
/* STATE CONTROL */ ,next_state
/* ALU CONTROL */ ,in_alu_sel1, in_alu_sel2, ALU_OP
/* OTHER */ ,memio_address_select
/************* OUTPUT TO REGISTERS ************/
/* */ , reg_write_addr,DE_reg_read_port2_addr, DE_reg_read_port1_addr
`ifdef CALCULATE_IPC
/* STATISTICS */ , new_instruction
`endif
);
assign Wbit=INSTRUCTION_INFO[2:2];
assign Sbit=INSTRUCTION_INFO[1:1];
assign opcode_size=INSTRUCTION_INFO[0:0];
/*############ Registers ######################################################## */
assign DE_reg_write_addr=DE_REGISTER_CONTROL[11:8];
assign DE_reg_read_port1_addr=DE_REGISTER_CONTROL[7:4];
assign DE_reg_read_port2_addr=DE_REGISTER_CONTROL[3:0];
assign DE_HALT=DECODER_SIGNALS[0:0];
assign DE_ERROR=DECODER_SIGNALS[1:1];
wire [3:0] reg_read_port1_addr;
assign reg_read_port1_addr = use_exec_reg_addr ? EXEC_reg_read_port1_addr : DE_reg_read_port1_addr;
reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr;
wire [15:0] reg_read_port1_data, reg_read_port2_data;
/*############ REGISTERS ########################################################## */
reg [15:0] CIR;
reg [15:0] PARAM1;
reg [15:0] PARAM2;
// verilator lint_off UNDRIVEN
reg [15:0] FLAGS;
// verilator lint_on UNDRIVEN
//Architectural Register file
reg [3:0] reg_write_addr;
wire [15:0] reg_write_data;
reg reg_write_we;
reg [3:0] reg_read_port1_addr;
reg [15:0] reg_read_port1_data;
reg [3:0] reg_read_port2_addr;
reg [15:0] reg_read_port2_data;
reg [1:0] reg_write_in_sel;
mux4 #(.WIDTH(16)) REG_FILE_WRITE_IN_MUX(
ALU_1O,
16'hz,
16'hz,
16'hz,
reg_write_in_sel,
reg_write_data);
register_file register_file(
.write_port1_addr(reg_write_addr),
.write_port1_data(reg_write_data),
.write_port1_we(reg_write_we),
.read_port1_addr(reg_read_port1_addr),
.read_port1_data(reg_read_port1_data),
.read_port2_addr(reg_read_port2_addr),
.read_port2_data(reg_read_port2_data)
);
/* WRITE */ .write_port1_addr(reg_write_addr), //TODO: should this come from exec instead?
/* */ .write_port1_data(ALU_O),
/* */ .write_port1_we(reg_write_we),
/* READ 1 */ .read_port1_addr(reg_read_port1_addr),
/* */ .read_port1_data(reg_read_port1_data),
/* READ 2 */ .read_port2_addr(DE_reg_read_port2_addr),
/* */ .read_port2_data(reg_read_port2_data),
/* GENERAL */ .clock(clock)
);
reg [15:0] ProgCount;
/*############ ALU / Execution units ########################################################## */
// ALU 1
reg [1:0] in_alu1_sel1;
reg [1:0] in_alu1_sel2;
/* OUT_MOD : { EXTRA_FUNCTIONS_BIT[0:0], MOD_OR_EXTRA_FUNCTION[1:0] } */
reg [2:0] IN_MOD;
reg [2:0] OUT_MOD;
mux4 #(.WIDTH(16)) MUX16_1A(
/*0*/ PARAM1,
/*1*/ reg_read_port1_data,
/*2*/ ProgCount[15:0],
/*3*/ 16'd0, /*0 Constant*/
in_alu1_sel1,
ALU_1A);
mux4 #(.WIDTH(16)) MUX16_1B(
/*0*/ PARAM2,
/*1*/ reg_read_port2_data,
/*2*/ ProgCount[15:0],
/*3*/ 16'd0, /*0 Constant*/
in_alu1_sel2,
ALU_1B);
wire [15:0] ALU_1A;
wire [15:0] ALU_1B;
wire [15:0] ALU_1O;
reg [`ALU_OP_BITS-1:0]ALU_1OP;
wire [7:0] ALU_1FLAGS;
ALU ALU1(
.A(ALU_1A),
.B(ALU_1B),
.OUT(ALU_1O),
.op(ALU_1OP),
.FLAGS(ALU_1FLAGS),
.Wbit(Wbit)
);
/*############ Processor state machine ########################################################## */
/*** RESET LOGIC ***/
/* verilator lint_off MULTIDRIVEN */
always @(negedge reset) begin
state <= `PROC_HALT_STATE; //TODO: race condition ??
end
always @(posedge reset) begin
state <= `PROC_RESET;
end
/* verilator lint_on MULTIDRIVEN */
/*** Processor stages ***/
`define invalid_instruction state <= `PROC_IF_STATE_ENTRY;ERROR <= 1;
always @(posedge clock) begin
case(state)
`PROC_RESET:begin
ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
ProgCount <= 'hFFF0;//TODO: Implement Segmentation and set to zero
HALT <= 0;
ERROR <= 0;
SIMPLE_MICRO <= 0;
reg_write_we <= 1;
instruction_size_init <= 1;
state <= `PROC_IF_STATE_ENTRY;
end
`PROC_HALT_STATE:begin
end
`PROC_IF_STATE_ENTRY:begin
BHE <= 0;
external_address_bus <= {4'b0,ProgCount};
IOMEM <= 0;
read <= 0;
write <= 1;
reg_write_we <= 1;
state <= `PROC_IF_WRITE_CIR;
reg_write_in_sel <= 2'b00;
end
`PROC_IF_WRITE_CIR:begin
`ifdef DEBUG_PC_ADDRESS
/* Weird (possible bug) where even though the
* testbench stop the clock after ERROR gets
* raised the logic for the rising edge still
* gets triggered printing this debug message. */
if(ERROR!=1)begin
if(instruction_size==1)
$display("Fetched instruction at %0x",ProgCount - 1);
else
$display("Fetched instruction at %0x",ProgCount - 0);
end
`endif
/*I built the entire decode stage with CIR
* being big endian so just convert it here*/
if(instruction_size==1)begin
/*Half on CIR half on this address */
state <= `PROC_DE_STATE_ENTRY;
if(ProgCount[0:0]==1)begin
CIR <= {CIR[7:0],external_data_bus[15:8]};
end else begin
CIR <= {CIR[7:0],external_data_bus[7:0]};
end
ProgCount <= ProgCount+1;
end else begin
if(ProgCount[0:0]==1)begin
/* Half on this address half on the next*/
ProgCount <= ProgCount+1;
CIR[15:8] <= external_data_bus[15:8];
state <= `PROC_IF_STATE_EXTRA_FETCH_SET;
end else begin
/* Both on this address! */
ProgCount <= ProgCount+2;
CIR <= {external_data_bus[7:0],external_data_bus[15:8]};
state <= `PROC_DE_STATE_ENTRY;
end
end
end
`PROC_IF_STATE_EXTRA_FETCH_SET:begin
external_address_bus <= {4'b0,ProgCount};
BHE <= 0;
state <= `PROC_IF_STATE_EXTRA_FETCH;
end
`PROC_IF_STATE_EXTRA_FETCH:begin
CIR[7:0] <= external_data_bus[7:0];
ProgCount <= ProgCount+1;
state <= `PROC_DE_STATE_ENTRY;
end
`PROC_DE_STATE_ENTRY:begin
external_address_bus <= {4'b0,ProgCount};
if(SIMPLE_MICRO==0)begin
/*This flag is set at reset and jump because
* at IF we need to know the size of the
* previous instruction (specifically if it was
* a single byte and the value would be
* incorrect in both cases. So when it gets
* set reset it only at the start of the next
* 8086 instruction */
instruction_size_init <= 0;
/* We cannot set these directly within
* microcode so don't overwrite useful values
* each time the next microcode is executed.
* Note this still allows to set initial values
* at the start of the microcode */
PARAM1 <= DE_PARAM1;
PARAM2 <= DE_PARAM2;
end
ERROR <= DE_ERROR;
HALT <= DE_HALT;
reg_read_port1_addr <= DE_reg_read_port1_addr;
reg_read_port2_addr <= DE_reg_read_port2_addr;
reg_write_addr <= DE_reg_write_addr;
if ( (ucode_seq_addr==`UCODE_NO_INSTRUCTION) && (ucode_seq_addr_entry!=`UCODE_NO_INSTRUCTION) )begin
/*switch to microcode decoding*/
ucode_seq_addr <= ucode_seq_addr_entry;
SIMPLE_MICRO <= 1;
/*keep state the same and rerun decode this time with all the data from the microcode rom*/
end else begin
state <= next_state;
end
end
`PROC_DE_LOAD_REG_TO_PARAM:begin
PARAM2<=reg_read_port2_data;
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end
`PROC_DE_LOAD_8_PARAM:begin
if(opcode_size==0)begin
if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/
PARAM1 <= {{8{CIR[7:7]}},CIR[7:0]};
end else begin
PARAM1[7:0] <= CIR[7:0];
end
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end else begin
if(ProgCount[0:0]==1)begin
if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/
PARAM1 <= {{8{external_data_bus[15:15]}},external_data_bus[15:8]};
end else begin
PARAM1[7:0] <= external_data_bus[15:8];
end
end else begin
if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/
PARAM1 <= {{8{external_data_bus[7:7]}},external_data_bus[7:0]};
end else begin
PARAM1[7:0] <= external_data_bus[7:0];
end
end
ProgCount <= ProgCount+1;
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end
end
`PROC_DE_LOAD_16_PARAM:begin
if(opcode_size==0)begin
PARAM1[7:0] <= CIR[7:0];
if(ProgCount[0:0]==1)begin
PARAM1[15:8] <= external_data_bus[15:8];
end else begin
PARAM1[15:8] <= external_data_bus[7:0];
end
ProgCount <= ProgCount+1;
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end else begin
if(ProgCount[0:0]==1)begin
ProgCount <= ProgCount+1;
PARAM1[7:0] <= external_data_bus[15:8];
state <= `PROC_DE_LOAD_16_EXTRA_FETCH_SET;
end else begin
PARAM1 <= external_data_bus;
ProgCount <= ProgCount+2;
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end
end
end
`PROC_DE_LOAD_16_EXTRA_FETCH_SET:begin
external_address_bus <= {4'b0,ProgCount};
state <= `PROC_DE_LOAD_16_EXTRA_FETCH;
end
`PROC_DE_LOAD_16_EXTRA_FETCH:begin
ProgCount <= ProgCount+1;
PARAM1[15:8] <= external_data_bus[7:0];
case(IN_MOD)
3'b000,3'b001,3'b010: state <= `PROC_MEMIO_READ;
default: state <= `PROC_EX_STATE_ENTRY;
endcase
end
`PROC_MEMIO_READ:begin
/*Decode MOD R/M, read the data and place it to PARAM1*/
case (IN_MOD)
3'b000,
3'b001,
3'b010:begin
case (RM)
3'b000:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b001:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b010:begin
/*[BP]+[SI]*/
`invalid_instruction
end
3'b011:begin
/*[BP]+[DI]*/
`invalid_instruction
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
state <= `PROC_MEMIO_READ_SETADDR;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
state <= `PROC_MEMIO_READ_SETADDR;
end
3'b110:begin
/*d16 */
`invalid_instruction
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
state <= `PROC_MEMIO_READ_SETADDR;
end
endcase
if(IN_MOD!=3'b000)begin
/*Actually check if 01 and add the 8bits or if 10 add the 16bits ....*/
`invalid_instruction;
end
end
3'b110:begin /* SP Indirect read*/
reg_read_port1_addr <= 4'b1100;
state <= `PROC_MEMIO_READ_SETADDR;
end
default:begin
`invalid_instruction
end
endcase
end
`PROC_MEMIO_READ_SETADDR:begin
if(memio_address_select==0)
external_address_bus <= {4'b0,reg_read_port1_data[15:0]};
else
external_address_bus <= {4'b0,ALU_1O};
state <= (memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])?`PROC_MEMIO_GET_UNALIGNED_DATA:`PROC_MEMIO_GET_ALIGNED_DATA;
end
`PROC_MEMIO_GET_ALIGNED_DATA:begin
PARAM2 <= (Wbit==1)? external_data_bus : {8'b0,external_data_bus[7:0]} ;
state <= `PROC_EX_STATE_ENTRY;
end
`PROC_MEMIO_GET_UNALIGNED_DATA:begin
PARAM2 <= {8'b0,external_data_bus[15:8]};
if(Wbit==1) begin
state <= `PROC_MEMIO_GET_SECOND_BYTE;
end else begin
state <= `PROC_EX_STATE_ENTRY;
end
end
`PROC_MEMIO_GET_SECOND_BYTE:begin
external_address_bus <= external_address_bus+1;
state <= `PROC_MEMIO_GET_SECOND_BYTE1;
end
`PROC_MEMIO_GET_SECOND_BYTE1:begin
PARAM2[15:8] <= external_data_bus[7:0];
state <= `PROC_EX_STATE_ENTRY;
end
`PROC_EX_STATE_ENTRY:begin
external_address_bus <= {4'b0,ProgCount};
FLAGS[7:0] <= ALU_1FLAGS[7:0];
case(OUT_MOD)
3'b000,
3'b001,
3'b010 : begin
if(memio_address_select==1)
state <= `PROC_MEMIO_WRITE;
else
case (RM) /* Duplicate code with write... */
3'b000:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b001:begin
/*[BX]+[SI]*/
`invalid_instruction
end
3'b010:begin
/*[BP]+[SI]*/
`invalid_instruction
end
3'b011:begin
/*[BP]+[DI]*/
`invalid_instruction
end
3'b100:begin
/*[SI]*/
reg_read_port1_addr <= 4'b1110;
state <= `PROC_MEMIO_WRITE;
end
3'b101:begin
/*[DI]*/
reg_read_port1_addr <= 4'b1111;
state <= `PROC_MEMIO_WRITE;
end
3'b110:begin
/*d16 */
`invalid_instruction
end
3'b111:begin
/*[BX]*/
reg_read_port1_addr <= 4'b1011;
state <= `PROC_MEMIO_WRITE;
end
endcase
end
3'b011:begin
reg_write_we <= 0;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY;
else
state <= `PROC_NEXT_MICROCODE;
end
3'b100:begin /*No output*/
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY;
else
state <= `PROC_NEXT_MICROCODE;
end
3'b101:begin /* Program Counter*/
ProgCount <= ALU_1O[15:0];
instruction_size_init <= 1;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY;
else
state <= `PROC_NEXT_MICROCODE;
end
3'b110:begin /* SP Indirect write*/
reg_read_port1_addr <= 4'b1100;
state <= `PROC_MEMIO_WRITE;
end
3'b111:begin /* Write to PRAM1 (for microcode calculations) */
PARAM1 <= ALU_1O;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY;
else
state <= `PROC_NEXT_MICROCODE;
end
default:begin
`invalid_instruction
end
endcase
end
`PROC_MEMIO_WRITE:begin
/* if memio_address_select == 0 ADDRESS: reg_read_port1_data DATA:ALU1_O */
/* if memio_address_select == 1 ADDRESS: ALU1_O DATA: reg_read_port1_data */
`ifdef DEBUG_MEMORY_WRITES
$display("Writing at %04x , %04x",reg_read_port1_data,ALU_1O);
`endif
if(memio_address_select==0)
external_address_bus <= {4'b0,reg_read_port1_data[15:0]};
else
external_address_bus <= {4'b0,ALU_1O};
IOMEM <= MEM_OR_IO;
state <= (Wbit==0) ? `PROC_MEMIO_PUT_BYTE : (reg_read_port1_data[0:0]?`PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:`PROC_MEMIO_PUT_ALIGNED_16BIT_DATA) ;
end
`PROC_MEMIO_PUT_UNALIGNED_16BIT_DATA:begin
read <= 1;
BHE <= 0;
if(memio_address_select==0)
data_bus_output_register <= {ALU_1O[7:0],ALU_1O[15:8]};
else
data_bus_output_register <= {reg_read_port1_data[7:0],reg_read_port1_data[15:8]};
state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT;
end
`PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT:begin
write <= 0;
state <= `PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2;
end
`PROC_MEMIO_PUT_UNALIGNED_PREP_NEXT2:begin
write <= 1;
external_address_bus <= external_address_bus+1;
BHE <= 1;
state <= `PROC_MEMIO_WRITE_EXIT;
end
`PROC_MEMIO_PUT_ALIGNED_16BIT_DATA:begin
read <= 1;
data_bus_output_register <= {ALU_1O[15:8],ALU_1O[7:0]};
state <= `PROC_MEMIO_WRITE_EXIT;
end
`PROC_MEMIO_PUT_BYTE:begin
read <= 1;
state <= `PROC_MEMIO_WRITE_EXIT;
if((memio_address_select?ALU_1O[0:0]:reg_read_port1_data[0:0])==0) begin
BHE <= 1;
if(memio_address_select==0)
data_bus_output_register <= {8'b0,ALU_1O[7:0]};
else
data_bus_output_register <= {8'b0,reg_read_port1_data[7:0]};
end else begin
BHE <= 0;
if(memio_address_select==0)
data_bus_output_register <= {ALU_1O[7:0],8'b0};
else
data_bus_output_register <= {reg_read_port1_data[7:0],8'b0};
end
end
`PROC_MEMIO_WRITE_EXIT:begin
write <= 0;
if (ucode_seq_addr==`UCODE_NO_INSTRUCTION)
state <= `PROC_IF_STATE_ENTRY;
else
state <= `PROC_NEXT_MICROCODE;
end
`PROC_NEXT_MICROCODE:begin
read <= 0;
write <= 1; // maybe we are coming from MEMIO_WRITE
BHE <= 0;
ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/
if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin
/*Finished microcode*/
SIMPLE_MICRO <= 0;
state <= `PROC_IF_STATE_ENTRY;
end else begin
state <= `PROC_DE_STATE_ENTRY;
end
reg_write_we <= 1;
end
default:begin
end
endcase
end
`undef invalid_instruction
/*############################################################################### */
endmodule

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -21,7 +21,8 @@
/* Register address format:
* [W-bit] [ 3-bit address] */
module register_file (write_port1_addr,write_port1_data,write_port1_we,read_port1_addr,read_port1_data,read_port2_addr,read_port2_data);
module register_file (write_port1_addr,write_port1_data,write_port1_we,read_port1_addr,read_port1_data,read_port2_addr,read_port2_data,clock);
input clock;
input [3:0] write_port1_addr;
input [3:0] read_port1_addr;
input [3:0] read_port2_addr;
@ -32,67 +33,70 @@ input write_port1_we;
reg [15:0] registers [7:0];
assign read_port1_data[15:8] = read_port1_addr[3:3] ? registers[read_port1_addr[2:0]][15:8] : 8'hz ;
assign read_port1_data[15:8] = read_port1_addr[3:3] ? registers[read_port1_addr[2:0]][15:8] : 8'h0 ;
assign read_port1_data[7:0] = ( read_port1_addr[3:3] ? registers[read_port1_addr[2:0]][7:0] :
( read_port1_addr[2:2] ? registers[ {1'b0,read_port1_addr[1:0]} ][15:8] : registers[ {1'b0,read_port1_addr[1:0]} ][7:0] ) );
assign read_port2_data[15:8] = read_port2_addr[3:3] ? registers[read_port2_addr[2:0]][15:8] : 8'hz ;
assign read_port2_data[15:8] = read_port2_addr[3:3] ? registers[read_port2_addr[2:0]][15:8] : 8'h0 ;
assign read_port2_data[7:0] = ( read_port2_addr[3:3] ? registers[read_port2_addr[2:0]][7:0] :
( read_port2_addr[2:2] ? registers[ {1'b0,read_port2_addr[1:0]} ][15:8] : registers[ {1'b0,read_port2_addr[1:0]} ][7:0] ) );
`ifdef DEBUG_REG_WRITES
string debug_name;
reg [2:0] debug_address;
`endif
wire write_Wbit;
assign write_Wbit=write_port1_addr[3:3];
always @(negedge write_port1_we) begin
if(write_Wbit==1)begin
/* Word : AX,CX,DX,BX,SP,BP,SI,DI */
registers[write_port1_addr[2:0]] <= write_port1_data;
end else begin
/* Byte : AL,CL,DL,BL,AX,CX,DX,BX */
if(write_port1_addr[2:2]==1)begin
/* Byte */
registers[ {1'b0,write_port1_addr[1:0]} ][15:8] <= write_port1_data[7:0];
always @(posedge clock) begin
if(write_port1_we==0)begin
if(write_Wbit==1)begin
/* Word : AX,CX,DX,BX,SP,BP,SI,DI */
registers[write_port1_addr[2:0]] <= write_port1_data;
end else begin
/* Byte */
registers[ {1'b0,write_port1_addr[1:0]} ][7:0] <= write_port1_data[7:0];
/* Byte : AL,CL,DL,BL,AX,CX,DX,BX */
if(write_port1_addr[2:2]==1)begin
/* Byte */
registers[ {1'b0,write_port1_addr[1:0]} ][15:8] <= write_port1_data[7:0];
end else begin
/* Byte */
registers[ {1'b0,write_port1_addr[1:0]} ][7:0] <= write_port1_data[7:0];
end
end
end
`ifdef DEBUG_REG_WRITES
// Icarus Verilog really doesn't like non-blocking assignments
// here
/* verilator lint_off BLKSEQ */
if(write_port1_addr[3:2]==2'b11)begin
case(write_port1_addr[1:0])
2'b00: debug_name="sp";
2'b01: debug_name="bp";
2'b10: debug_name="si";
2'b11: debug_name="di";
endcase
end else begin
case(write_port1_addr[1:0])
2'b00: debug_name="ax";
2'b01: debug_name="cx";
2'b10: debug_name="dx";
2'b11: debug_name="bx";
endcase
end
/* verilator lint_on BLKSEQ */
`endif
`ifdef DEBUG_REG_WRITES
// Icarus Verilog really doesn't like non-blocking assignments
// here
/* verilator lint_off BLKSEQ */
if(write_port1_addr[3:2]==2'b11)begin
case(write_port1_addr[1:0])
2'b00: debug_name="sp";
2'b01: debug_name="bp";
2'b10: debug_name="si";
2'b11: debug_name="di";
endcase
end else begin
case(write_port1_addr[1:0])
2'b00: debug_name="ax";
2'b01: debug_name="cx";
2'b10: debug_name="dx";
2'b11: debug_name="bx";
endcase
end
/* verilator lint_on BLKSEQ */
if (write_Wbit)
debug_address<=write_port1_addr[2:0];
else
debug_address<={1'b0,write_port1_addr[1:0]};
`endif
end
end
`ifdef DEBUG_REG_WRITES
always @(posedge write_port1_we) begin
if ( debug_name != "" ) /*At the start this triggers for some reason */
if (write_Wbit)begin
$display("register %%%s update to $0x%04x",debug_name,registers[write_port1_addr[2:0]]);
end else begin
$display("register %%%s update to $0x%04x",debug_name,registers[{1'b0,write_port1_addr[1:0]}]);
end
$display("register %%%s update to $0x%04x",debug_name,registers[debug_address]);
end
`endif

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -18,63 +18,214 @@
along with this program. If not, see <http://www.gnu.org/licenses/>. */
`timescale 1ns/1ps
`include "error_header.v"
`include "config.v"
module system ( input clock,input reset, output [19:0]address_bus, inout [15:0]data_bus,output BHE, output rd, output wr, output IOMEM, output HALT, output ERROR);
processor p(clock,reset,address_bus,data_bus,rd,wr,BHE,IOMEM,HALT,ERROR);
module system ( input clock,input reset, output [19:0]address_bus, output [15:0]data_bus_write ,output BHE, output rd, output wr, output IOMEM, output HALT, output [`ERROR_BITS-1:0] ERROR);
doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM);
`ifdef CALCULATE_IPC
wire new_instruction;
`endif
`ifdef OUTPUT_JSON_STATISTICS
wire unsigned [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT;
wire VALID_INSTRUCTION_STAT,jump_req;
`endif
wire [15:0]data_bus_read_CPU,data_bus_write_CPU;
assign data_bus_read_CPU=(IOMEM==0)?data_bus_read_RAM:data_bus_IO;
assign data_bus_write=data_bus_write_CPU;
wire wait_state=1'b0;
processor p(
/* MISC */ clock,reset,HALT,ERROR
/* MEMORY / IO */ ,address_bus,data_bus_read_CPU,data_bus_write_CPU,wait_state,rd,wr,BHE,IOMEM
`ifdef CALCULATE_IPC
/* STATISTICS */ ,new_instruction
`endif
`ifdef OUTPUT_JSON_STATISTICS
/* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT, jump_req
`endif
);
wire [15:0] data_bus_read_RAM;
doublemem #(.RAM_SIZE_IN_BYTES(65536)) sysmem(address_bus[15:0],data_bus_read_RAM,data_bus_write_CPU,rd,wr,BHE,IOMEM,clock);
`ifdef OUTPUT_JSON_STATISTICS
string stats_name,version,commit;
integer json_file_descriptor;
`endif
`ifndef YOSYS
string waveform_name;
`endif
initial begin
if($value$plusargs("WAVEFORM=%s",waveform_name))begin
$dumpfile(waveform_name);
$dumpvars(0,p);
end
`ifndef SYNTHESIS
if($value$plusargs("WAVEFORM=%s",waveform_name))begin
$dumpfile(waveform_name);
$dumpvars(0,p,cycles);
end
`ifdef OUTPUT_JSON_STATISTICS
if(!$value$plusargs("VERSION=%s",version)) version="unkown";
if(!$value$plusargs("COMMIT=%s",commit)) commit="unkown";
if($value$plusargs("STATS=%s",stats_name))begin
json_file_descriptor=$fopen(stats_name,"w");
$fdisplay(json_file_descriptor,"{\n\"L1_size\":%0d,\n\"9086 verison\":\"%s\",\n\"latest commit\":\"%s\",\n\"Cycles\":[",$rtoi($pow(2,`L1_CACHE_SIZE)),version,commit);
first_json_cycle = 1;
end else
json_file_descriptor=0;
`endif
sane=0;
finish=0;
`endif
end
//integer killswitch=0;
//always @(posedge clock) begin
// killswitch <= killswitch +1;
// if( killswitch == 20000 )begin
// if($value$plusargs("MEMDUMP=%s",memdump_name))begin
// $writememh(memdump_name, system.sysmem.memory,0,32767);
// end
// $finish;
// end
//end
`ifdef OUTPUT_JSON_STATISTICS
reg first_json_cycle;
always @(negedge clock)begin
if(finish < 2 && json_file_descriptor!=0 && sane)begin
$fdisplay(json_file_descriptor,"%s{\"C\":%0d,\"L1\":%0d,\"VDI\":%0d,\"JMP\":%0d}",first_json_cycle?"":",",cycles,L1_SIZE_STAT,VALID_INSTRUCTION_STAT,jump_req);
first_json_cycle <= 0;
end
end
`endif
reg [15:0]data_bus_IO;
`ifndef SYNTHESIS
always @(negedge wr) begin
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )
$write("%s" ,data_bus[15:8]);
end
reg [1:0] finish;
string memdump_name;
always @(posedge HALT) begin
$display("Processor halted.\nCycles run for: %d",cycles-1);
if($value$plusargs("MEMDUMP=%s",memdump_name))begin
$writememh(memdump_name, sysmem.memory,0,32767);
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
$write("%s" ,data_bus_write[15:8]);
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
if(data_bus_write[0:0]==1)
$display("\x1b[7mLed turned on\x1b[m\n");
else
$display("\x1b[7mLed turned off\x1b[m\n");
end
finish<=2'd1;
end
always @(posedge clock) begin
/* Allow some clock cycles for the waveform*/
case(finish)
2'd0: begin end
2'd1: finish <= 2;
2'd2: finish <= 3;
2'd3: $finish;
endcase
end
always @(posedge ERROR) begin
$display("PROCESSOR RUN INTO AN ERROR.\nCycles run for: %d",cycles-1);
if($value$plusargs("MEMDUMP=%s",memdump_name))begin
$writememh(memdump_name, system.sysmem.memory,0,32767);
always @(negedge rd) begin
if(IOMEM==1'b1 && address_bus[7:1]==7'h10 )begin // 0xABCD on address 0x20
data_bus_IO<=16'hABCD;
end else begin
data_bus_IO<=16'h0000;
end
finish<=2'd1;
end
`endif
integer cycles=0;
always @(posedge clock)begin
if(reset==1)
cycles<=cycles+1;
else
cycles<=0;
`ifdef CALCULATE_IPC
/* verilator lint_off MULTIDRIVEN */
reg [128:0] instruction_count;
/* verilator lint_on MULTIDRIVEN */
always @(new_instruction) begin
instruction_count<=instruction_count+1;
end
`endif
`ifndef SYNTHESIS
`ifdef OUTPUT_JSON_STATISTICS
reg [128:0] instruction_count_temp;
`endif
string memdump_name;
always @(posedge HALT) begin
if($value$plusargs("MEMDUMP=%s",memdump_name))begin
$writememh(memdump_name, sysmem.memory,0,32767);
end
finish<=2'd1;
end
/* verilator lint_off MULTIDRIVEN */
reg [1:0] finish;
/* verilator lint_on MULTIDRIVEN */
reg sane;
reg [128:0] cycles;
always @(posedge reset)begin
sane<=1;
end
always @(posedge clock) begin
/* Allow some clock cycles for the waveform*/
case(finish)
2'd0: begin end
2'd1: begin
finish <= 2;
/* instruction_count gets updated at the sme time as HALT is pulled so wait a clock cycle to get an accurate reading*/
$display("\x1b[7mProcessor halted.\nCycles run for : %0d\x1b[m",cycles);
`ifdef CALCULATE_IPC
$display("\x1b[7mInstr. per cycle : %f\x1b[m", $itor(instruction_count) / $itor(cycles) );
`endif
`ifdef OUTPUT_JSON_STATISTICS
instruction_count_temp <= instruction_count;
`endif
end
2'd2: begin
finish <= 3;
`ifdef OUTPUT_JSON_STATISTICS
if(json_file_descriptor!=0)
$fdisplay(json_file_descriptor,"],\n\"Total Cycles\":%0d,\n\"Instructions run\":%0d\n}",cycles-1,instruction_count_temp);
`endif
$finish;
end
2'd3: begin
end
endcase
end
always @( ERROR ) begin
if ( ERROR != `ERR_NO_ERROR && sane == 1 ) begin
$display("PROCESSOR RUN INTO AN ERROR.");
case (ERROR)
default:begin
end
`ERR_UNIMPL_INSTRUCTION:begin
$display("Unimplemented instruction");
end
`ERR_UNIMPL_ADDRESSING_MODE: begin
$display("Unimplemented addressing mode");
end
endcase
$display("Cycles run for: %0d",cycles-1);
if($value$plusargs("MEMDUMP=%s",memdump_name))begin
$writememh(memdump_name, system.sysmem.memory,0,32767);
end
finish<=2'd1;
end
end
always @(negedge clock)begin
if(reset==1)
cycles<=cycles+1;
else begin
cycles<=0;
`ifdef OUTPUT_JSON_STATISTICS
instruction_count <= 0;
`endif
end
end
`endif
endmodule

View File

@ -36,6 +36,7 @@ int main(int argc, char** argv) {
tick();
system_state->reset=0;
tick();
tick();
system_state->reset=1;
// Simulate until $finish

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -25,15 +25,15 @@ wire clock;
reg reset;
reg clk_enable;
wire [19:0]address_bus;
wire [15:0]data_bus;
wire [15:0]data_bus_write;
wire rd,wr,HALT;
wire ERROR;
wire [2:0] ERROR;
wire IOMEM;
system system( .clock(clock),
.reset(reset),
.address_bus(address_bus),
.data_bus(data_bus),
.data_bus_write(data_bus_write),
.rd(rd),
.wr(wr),
.HALT(HALT),
@ -46,13 +46,31 @@ clock_gen #(.FREQ(1000)) u1(clk_enable, clock);
string memdump_name;
initial begin
clk_enable = 1;
do_reset = 0;
end
reset = 1;
#(`CPU_SPEED*2)
reset = 0;
#($random%1000)
#(`CPU_SPEED)
reset = 1;
reg [2:0]do_reset;
always @(posedge clock) begin
case(do_reset)
3'd0:begin
do_reset<=1;
end
3'd1:begin
do_reset<=2;
reset <= 0;
end
3'd2:begin
do_reset<=3;
reset <= 0;
end
3'd3:begin
do_reset<=4;
reset <= 1;
end
3'd4:begin
end
endcase
end
endmodule

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project.
Copyright (c) 2023 Efthymios Kritikos
Copyright (c) 2024 Efthymios Kritikos
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by

View File

@ -0,0 +1,21 @@
# This file is basically to make verilator compilation look pretty.
# If the project doesn't compile it might be because verilator handles compilation
# differently and this patch doesn't work anymore. In such case remove everything
# except the include Vfpga_top.mk line and try again.
VM_DEFAULT_RULES=0
include Vfpga_top.mk
include ../../../common.mk
%.o: %.cpp
${QUIET_CC}
${Q}$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
$(VK_SLOW_OBJS): %.o: %.cpp
${QUIET_CC}
${Q}$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_SLOW) -c -o $@ $<
$(VK_GLOBAL_OBJS): %.o: %.cpp
${QUIET_CC}
${Q}$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_GLOBAL) -c -o $@ $<

66
tools/docker_build_tests.sh Executable file
View File

@ -0,0 +1,66 @@
#!/bin/sh
#
# docker_build_tests.sh - Tests the build process on various distributions with docker
#
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
set -eu
PROJDIRNAME=$(basename $(realpath "$(dirname "$0")"/..))
cd $(realpath "$(dirname "$0")"/../..)
FAILED=0
do_test(){
case "$1" in
"debian:stable"|"debian:latest")
SYSTEM_UPDATE="apt-get update ;apt-get -y install make bin86 xxd verilator g++ libz-dev"
;;
"ubuntu:latest")
SYSTEM_UPDATE="apt-get update ;apt-get -y install make bin86 xxd verilator g++ libz-dev libfindbin-libs-perl"
;;
"fedora:latest")
SYSTEM_UPDATE="dnf install -y make verilator dev86 g++ zlib-devel xxd"
;;
"archlinux:latest")
SYSTEM_UPDATE="pacman --noconfirm -Sy make verilator xxd bin86 gcc python"
;;
esac
if tar c "$PROJDIRNAME" | docker run -i "$1" bash -c 'set -eu;tar x ;'"$SYSTEM_UPDATE"'; cd 9086; make mrproper; if [ "$(make -j boot_code/gnome_sort.run| tail -n5|head -n 1)" = "06 09 17 18 1F 21 33 37 3A 3F 44 4F 51 51 54 5D 8B 99 A5 AE DB DF E9 EE " ];then echo pass;else echo failed check; exit 1;fi ' > /dev/null 2>/dev/null
then
return 0
else
return 1
fi
}
# ubuntu:latest has a version of verilator that is too old.
for i in debian:stable debian:latest fedora:latest archlinux:latest
do
printf 'Testing with docker image %s \t: ' "$i" |expand -t 44
if ! do_test "$i"
then
FAILED=1
printf '\e[1;31mFailed\e[0m\n'
else
printf '\e[1;32mPassed\e[0m\n'
fi
done
if [ "$FAILED" = 1 ]
then
exit 1
fi

246
tools/gen_litedram.sh Executable file
View File

@ -0,0 +1,246 @@
#!/bin/sh
#
# gen_litedram.sh - Downloads and generates the litedram verilog source code for a specific phy or for simulation
#
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
set -eu
SOURCE_CODE_URL=https://github.com/enjoy-digital/litedram/archive/refs/tags/2023.08.tar.gz
SOURCE_MD5_SUM=afc2208c08e60994d126c445574960da
PYTHON_APPIMAGE_URL=https://github.com/niess/python-appimage/releases/download/python3.9/python3.9.18-cp39-cp39-manylinux_2_28_x86_64.AppImage
PYTHON_APPIMAGE_SUM=8c383ade3ace416cf508d5f458b30149
OUTPUT_ECP5_1_WISHBONE_MD5=c775ddb23fd97211f3ace40d6e8c2a5f
OUTPUT_ECP5_1_WISHBONE_SIM_MD5=06d0b073d06937312b425767c1895c6c
help(){
echo This scripts generates a verilog file from the litedram project
echo It is currently hardcoded for the ECP5 PHY
echo
echo Usage:
echo \ \ \ "$0" \<output verilog file\>
}
STOP_PARSING=0
OUT_FILE=""
QUIET=0
FORCE=0
SIMULATION=0
while [ $# -gt 0 ]; do
if [ "$STOP_PARSING" = "1" ]
then
echo arguments after --
help
exit 1
fi
case $1 in
-q|--quiet)
QUIET="$1"
shift
;;
-h|--help)
help
exit 0
;;
-f|--force)
FORCE=1
shift
;;
-s|--simulation)
SIMULATION=1
shift
;;
--)
if ! [ $# -gt 1 ]
then
echo No file after --
help
exit 1
fi
if [ "$OUT_FILE" ]
then
echo Error two output files given
exit 1
fi
OUT_FILE=$2
STOP_PARSING=1
shift
shift
;;
-*)
echo "Unknown option $1"
help
exit 1
;;
*)
if [ "$OUT_FILE" ]
then
echo Error two output files given
exit 1
fi
OUT_FILE=$1
shift # past argument
;;
esac
done
if [ "$OUT_FILE" = "" ]
then
echo Error: No output file provided
help
exit 1
fi
TEMP_DIR=$(mktemp -d)
trap 'rm -rf -- "$TEMP_DIR"' EXIT
CUR_DIR=$(pwd)
if ! echo "$OUT_FILE" | grep '^/' > /dev/null
then
OUT_FILE="${CUR_DIR}/${OUT_FILE}"
fi
cd "$TEMP_DIR"
if [ "$QUIET" = 0 ];then
echo Downloading litedram source code...
fi
wget --output-document=source.tar.gz --quiet "$SOURCE_CODE_URL"
if [ "$(md5sum source.tar.gz)" != "${SOURCE_MD5_SUM} source.tar.gz" ]
then
echo Downloaded litedram source downloaded doesn\'t match md5 sum
exit 1
fi
if [ "$QUIET" = 0 ];then
echo Downloading python appimage...
fi
wget --output-document=python.AppImage --quiet "$PYTHON_APPIMAGE_URL"
if [ "$(md5sum python.AppImage)" != "${PYTHON_APPIMAGE_SUM} python.AppImage" ]
then
echo Downloaded python appimage source doesn\'t match md5 sum
exit 1
fi
chmod a+x python.AppImage
./python.AppImage --appimage-extract >/dev/null
PYTHON=$(realpath squashfs-root/AppRun)
mkdir python_modules
PYTHON_MODULES=$(realpath python_modules)
######### This is a patch ############
# It's because litedram needs modules
# it doesn't really use for --sim and
# pip doesn't currently have some
wget --quiet https://github.com/enjoy-digital/litescope/archive/refs/tags/2023.08.tar.gz
tar xf 2023.08.tar.gz
mv litescope-2023.08/litescope/ "${PYTHON_MODULES}"
rm -r litescope-2023.08 2023.08.tar.gz
######################################
if [ "$QUIET" = 0 ];then
echo extracting the source...
fi
tar xvf source.tar.gz > source_dir
SOURCE_DIR=$(head -n 1 source_dir)
rm source_dir
if [ "$QUIET" = 0 ];then
echo patching the source...
fi
#Generate the following text by running this: (diff -Naur /dev/null examples/orangecrab_9086.yml | gzip -9 | base64 | tr -d '\n';echo)
echo H4sIAAAAAAACA61US2+bQBA+179ihC+JMA4Pg4mlSo7sOLFaJ5bjHKqqQguMYxRg6QJ2UJX/3lkwUeKop3oOy2pmvm/niaZpcBHi7iIt4/iLqZuWZpiaboJhj6zhaGD13aFOYthDUOWlo6oq4AtLshjzCy5Y+oSBYL53qbtOv0rekVhguCNzONKtvnM5HNqubtoHkvEYNL2ng2r0LAPG4476p6MCdOEGUxQsBu2/RfIplFkUoDKi6/fZtf2omfZMcxc3pmtPlB69N1veXEHj1a8RQVZKdxLljqdITh+kC5PlIxRVhnCGL7DDFxHlwa4HOQo6JeS85kkwkV7EpUynK+szz3R1taiJOmoTauLle5YpQIi1KOnlJp4k9EKMWSUNJLqMeg5ljsAg5nvYsbhEKDiwHY9CEMhCiHGHcZQ+NdRdWN7+OEFF36qah4IlXsLDMsamWMpiPTC+OYOF4chMu/BQp9e45MA3UGwRfM5ECFzAw702nS8Wn8i81Cc+s3dUqrsy8VFIFr8qEJ4EL7P8HZiG8LmBAhj/Bku397BsWx1aTarrydKmRlGlmgTWssUEqgeEtG0pZwJ/l5gGFZyklFGalYUXxM/ehojrcAYuOnWTpQmCmAfPsHl79efkfrW6nqx/NYlU+UcwgDOQcNmCKi8w+URwRq2RGPgKB/T5EWmURkchgdmSzsl2TNmWZsIFwummTE6+X242KGgBsmJLkRhO77A8UtGOVcCThKUhNM5tNI+0kbDkosjhFNHQwgkvk3QUR/2zIuU+yrc+rbyny+08aEnfbn5rb3a5NoWsYN4+Cut8LPNgeK2/8nzt/AU14UE3kwUAAA== | base64 -d | gzip -d > 00-add_orangecrab_config.patch
cd "$SOURCE_DIR"
patch -s -p0 < ../00-add_orangecrab_config.patch > /dev/null
if [ "$QUIET" = 0 ];then
echo Downloading required python modules...
fi
if ! "$PYTHON" -m pip install --target "$PYTHON_MODULES" install "pyaml==23.9.7" "migen==0.9.2" "litex==2023.08" "litedram==2023.8" "liteeth==2022.12" "liteiclink==2022.12" "pythondata_misc_tapcfg" > "$TEMP_DIR/build_log" 2> "$TEMP_DIR/build_log"
then
echo ERROR: Failed download python modules
cat "$TEMP_DIR/build_log"
exit 1
fi
if ! ./setup.py build > "$TEMP_DIR/build_log" 2> "$TEMP_DIR/build_log"
then
echo ERROR: Failed to run setup.py
cat "$TEMP_DIR/build_log"
exit 1
fi
cd build/lib/litedram/
GEN_OPTIONS=""
if [ $SIMULATION = 1 ]
then
GEN_OPTIONS="$GEN_OPTIONS --sim"
fi
if ! PYTHONPATH=$PYTHON_MODULES "$PYTHON" gen.py $GEN_OPTIONS ../../../examples/orangecrab_9086.yml --no-compile-software > "$TEMP_DIR/build_log" 2> "$TEMP_DIR/build_log"
then
echo ERROR: Failed to run gen.py
cat "$TEMP_DIR/build_log"
exit 1
fi
if [ "$QUIET" = 0 ];then
echo patching source file...
fi
if [ "$SIMULATION" = 0 ]
then
#This is just for some yosys warnings...
echo H4sIAAAAAAACA82T326CMBTG73mKc7XBECnKAHUkvMeyNEdatZE/hiLEzPnsa5nL4pYh3izrTduc3/d9Jyet4ziw3IuMuWuseYsVdzNRc1ZhTtOy4uMGJmQydTzPmYRAgrkfzEk4noYzEgZh5INN1DJs2waX8cYt9lkG3yWRUo1nj5FPvMALzpIkASci/nQUgt3tASSJASilWBfw+tmFboKylaA7j7YVwxpH8LNGzrU3iC+roqh5tcKU01bXF/8igOYot30pHaCjzFNfGG25tTCcvw4EzFo8SEjMBwuWfC0KA/S6UKabspRqyxltMBNMwlMM0T0jiyHwM3nRvHlBLbHY5phuRMHJFwt3YJpXwB0eshIZFVJfleK39BaLWh+k1dmehhpXKLXgNIxOUVrWDbyauuKP/V1jWotG/WFlbRzhholUHBnEcb+7hj6GMti3rRR51bijVM+Weljv0yEXHY0EAAA= | base64 -d | gzip -d | patch -s -p0
CHECK_MD5SUM=$OUTPUT_ECP5_1_WISHBONE_MD5
else
echo H4sIAAAAAAACA7WPOQ7CMBREe59ievPjPVvlC3AGMLGFIpkEZeP6pKBCoguvmPLNDBHhtvY5intY0itMSeR+SXEKj0s3TqnYAGipDSlNsoIqW2laVxWNaXTZWKfB5Q7jnEPEtIlhzRk/+BLZ1srCVLYuldPVR+Q9SJlTDb6ng/cMQtChMEbXpX+kuQs5QQ0zBNRzZsTo8Kp9PM5jXHP6x483iNz1Tr8BAAA= | base64 -d | gzip -d | patch -s -p0
CHECK_MD5SUM=$OUTPUT_ECP5_1_WISHBONE_SIM_MD5
fi
if ! [ "$(sed 's@//.*@@' build/gateware/litedram_core.v | md5sum )" = "$CHECK_MD5SUM -" ]
then
if [ "$FORCE" = 0 ]
then
echo ERROR: File was successfully built but the md5sum doesn\'t match the one used in development.
echo You can ignore this error by passing the --force flag
exit 1
else
echo WARNING: File was successfully built but the md5sum doesn\'t match the one used in development.
fi
fi
cp build/gateware/litedram_core.v "$OUT_FILE"
if [ "$QUIET" = 0 ];then
echo File built correctly!
fi

70
tools/parse_nextpnr_stats.sh Executable file
View File

@ -0,0 +1,70 @@
#!/bin/sh
#
# parse_nextpnr_stats.sh - Reads a nextpnr json report file and generates some basic statistics about the design
#
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
set -eu
if ! which jq &> /dev/null
then
echo to get statistics, please install jq
exit 0
fi
REPORT_TYPE=brief
if [ $# == 0 ]
then
echo $0' [report type] <report json file>'
exit 1
elif [ $# == 2 ]
then
case "$1" in
"--brief")
REPORT_TYPE=brief
;;
*)
echo unknown parameter "\"$1\""
exit 1
;;
esac
REPORT=$2
else
REPORT=$1
fi
if ! [ -e "$REPORT" ]
then
echo file "\"${REPORT}\"" doesn\'t exist!
exit 1
fi
LUT_AVAIL=$(jq '.utilization.TRELLIS_COMB.available' "$REPORT" )
LUT_USED=$(jq '.utilization.TRELLIS_COMB.used' "$REPORT" )
FF_AVAIL=$(jq '.utilization.TRELLIS_FF.available' "$REPORT" )
FF_USED=$(jq '.utilization.TRELLIS_FF.used' "$REPORT" )
FREQ_GOT=$(jq '.fmax."$glbnet$CPU_SPEED".achieved' "$REPORT" |grep -o '..\..')
FREQ_MAX=$(jq '.fmax."$glbnet$CPU_SPEED".constraint' "$REPORT" |grep -o '..\..')
if [ "$REPORT_TYPE" == "brief" ]
then
printf '\e[1;30m'
echo Luts $LUT_USED/$LUT_AVAIL \($(echo "($LUT_USED*100)/$LUT_AVAIL"|bc -l|grep -o '^.*\..')%\)
echo Flip Flops $FF_USED/$FF_AVAIL \($(echo "($FF_USED*100)/$FF_AVAIL"|bc -l|grep -o '^.*\..')%\)
echo Max CPU freq $FREQ_GOT/$FREQ_MAX
printf '\e[0m'
fi

92
tools/plot.sh Executable file
View File

@ -0,0 +1,92 @@
#!/bin/sh
#
# plot.sh - Parses the runtime simulation json data and plots them to an svg file
#
# Copyright (c) 2024 Efthymios Kritikos
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
set -euf
print_help(){
echo "$0 <json data file> <function> <output filename>"
echo " Possible functions:"
echo " cache_time : graph of cache utilisation in bytes over time in clock cycles"
echo " cache_util_freq : graph of the likelihood of the cache for each utilisation"
}
if [ "$#" != 3 ] || ! [ -e "$1" ]
then
print_help
exit 1
fi
CSV_FILE=$(mktemp)
IN=$1
OUT=$3
jq -r '.Cycles[]| [.C,.L1,.VDI,.JMP]|@csv' -- "$IN" > "$CSV_FILE"
BASE_GNUPLOT_OPTIONS="set datafile separator ',';set term svg;set output \"${OUT}\";"
parse_cache_size(){
CACHE_SIZE=$(jq -r .L1_size -- "$IN")
}
parse_total_cycles(){
TOTAL_CYCLES=$(jq -r .\"Total\ Cycles\" -- "$IN")
}
case "$2" in
"cache_time")
parse_cache_size
parse_total_cycles
gnuplot -e "${BASE_GNUPLOT_OPTIONS}\
set term svg name \"Cache_time\";\
set xlabel \"Clock cycles\";\
set ylabel \"Cache utilisation (bytes)\";\
set offsets 0, 0, 3, 1;\
set ytics 0,1,$((CACHE_SIZE-1));\
set xtics 0,$((TOTAL_CYCLES/15)),${TOTAL_CYCLES};\
unset colorbox;\
set ytics add (\"Valid\" -1);\
set grid ytics;\
set yrange [-2:${CACHE_SIZE}];\
set xrange [-10:${TOTAL_CYCLES}+9];\
set palette model RGB defined ( 0 'red', 1 'green', 2 'dark-khaki' );\
plot\
'${CSV_FILE}' using 1:(-2):(0):("'$'"4*100):(2) with vectors nohead palette notitle,\
'${CSV_FILE}' using 1:2 with histeps notitle ls 1,\
'${CSV_FILE}' using 1:(-0.75):(0):(-0.5):3 with vectors nohead palette notitle \
"
;;
"cache_util_freq")
parse_cache_size
gnuplot -e "${BASE_GNUPLOT_OPTIONS}\
set term svg name \"cache_util_freq\";\
set xlabel \"Utilisation (bytes)\";\
set ylabel \"Occurrences\";\
set boxwidth 0.5;\
set style fill solid 0.4;\
set xtics 0,1,$((CACHE_SIZE-1));\
set offsets 1, 2, 0, 0;\
plot '${CSV_FILE}' using 2:(1) smooth frequency with boxes notitle"
;;
*)
print_help;
exit 1
;;
esac