Compare commits

..

69 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
56 changed files with 4474 additions and 879 deletions

9
.gitignore vendored
View File

@ -6,9 +6,18 @@
*.swp *.swp
*.memdump *.memdump
*.json *.json
*.dfu
*.bit
*.fst.hier
abc.history
boot_code/*.bin boot_code/*.bin
boot_code/*.txt boot_code/*.txt
boot_code/*.stxt
system/boot_code.bin system/boot_code.bin
system/boot_code.txt system/boot_code.txt
system/obj_dir/ system/obj_dir/
system/simplified_ucode.txt
system/build/
tools/*svg 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. # 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 # 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 # 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 BOOT_CODE=boot_code/brainfuck_mandelbrot.txt
GTKWSAVE=./gtkwave_savefile.gtkw GTKWSAVE=./gtkwave_savefile.gtkw
MICROCODE=system/ucode.txt MICROCODE=system/ucode.txt
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} 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 NO_ASM=1
include common.mk include common.mk
@ -29,21 +30,63 @@ include common.mk
.PHONY: ${BOOTABLES} .PHONY: ${BOOTABLES}
.PHONY: ${subst .txt,.bin,${BOOTABLES}} .PHONY: ${subst .txt,.bin,${BOOTABLES}}
${BOOTABLES} ${subst .txt,.bin,${BOOTABLES}} : ${BOOTABLES} ${subst .stxt,.bin,${subst .txt,.bin,${BOOTABLES}}} :
${Q}make ${MAKEOPTS} -C boot_code $(subst boot_code/,,$@) ${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code $(subst boot_code/,,$@)
boot_code/%.txt: 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} .PHONY:${SYSTEM_VVP}
${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} .PHONY:${VERILATOR_BIN}
${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 .PHONY: clean
clean: clean:
${Q}make ${MAKEOPTS} -C system clean ${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system clean
${Q}make ${MAKEOPTS} -C boot_code 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

@ -13,26 +13,64 @@ A CPU that aims to be binary compatible with the 8086 ISA, focused on optimisati
* [X] Is pipelined * [X] Is pipelined
* [ ] Is Out of Order * [ ] Is Out of Order
* [ ] Is superscalar * [ ] Is superscalar
* [ ] Has been successfully synthesized * [X] Has been successfully synthesized
* [ ] Has a comprehensive testing framework
### Simulating it ### 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) 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) This list shows the software needed and the versions used during development :
* Icarus Verilog : version 12.0 OR **(preferred)** Verilator : 5.016 * Icarus Verilog : version 12.0 OR **(preferred)** Verilator : 5.018
* bin86 : 0.16.21 * bin86 : 0.16.21
* GNU Make : 4.4.1 * GNU Make : 4.4.1
* xxd : 2022-01-14 * xxd : 2023-10-25
* POSIX coreutils : GNU coreutils 9.4 * 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 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 ### High level design overview
<img width="700" style=" margin: 10px 0px 10px 10px;" alt="9086 logo" src="readme_files/9086_overview.svg"> <img width="700" style=" margin: 10px 0px 10px 10px;" alt="9086 logo" src="readme_files/9086_overview.svg">
### License ### License and Copyright
All parts of this project are licensed under the GNU General Public License version 3 or later 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 ### Version names
The version name consist of three numbers: The version name consist of three numbers:
@ -42,3 +80,4 @@ The version name consist of three numbers:
1. Patch level 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. 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,16 +1,39 @@
SOURCE=brainfuck_interpreted.asm brainfuck_compiled.asm brainfuck_mandelbrot.asm pipeline_ideal.asm fibonacci.asm gnome_sort.asm cache_fill_and_empty.asm # This file is part of the 9086 project.
BINARIES=$(subst .asm,.txt,${SOURCE}) #
# 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=${BINARIES}
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE}) BUILD_FILES+=$(subst .asm,.memdump,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.fst,${SOURCE}) BUILD_FILES+=$(subst .asm,.fst,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.bin,${SOURCE}) BUILD_FILES+=$(subst .asm,.bin,${SOURCE_FULL} ${SOURCE_SHORT})
BUILD_FILES+=$(subst .asm,.json,${SOURCE}) BUILD_FILES+=$(subst .asm,.json,${SOURCE_FULL} ${SOURCE_SHORT})
all: ${BINARIES} all: ${BINARIES}
brainfuck_interpreted.bin: brainfuck_interpreter_v0.asm hello_9086.bf.asm dos_layer.asm 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_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 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 fibonacci.bin: helpers.asm
gnome_sort.bin: helpers.asm gnome_sort.bin: helpers.asm
@ -24,3 +47,5 @@ include ../common.mk
clean: clean:
$(call QUIET_CLEAN,boot_code) $(call QUIET_CLEAN,boot_code)
${Q}rm -f $(BUILD_FILES) *.bf.asm ${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 ; Interrupt table and routines
INCLUDE dos_layer.asm
org 0x100 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: prog:
INCLUDE hello_9086.bf.asm INCLUDE hello_9086.bf.asm
output_program:
.ORG 0xFFF0 .ORG 0xFFF0
MOV AX,#0x0100 MOV AX,#0xF800
JMP AX 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. ; 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 ; 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 ; 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 ; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>. ; 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 bx,#bootup_msg
mov ah,#0x02 mov ah,#0x02
print1: print1:
@ -27,17 +29,27 @@ inc bx
cmp dl,#0x0A cmp dl,#0x0A
jne print1 jne print1
MOV DI,#0x0200
MOV AX,#0x0000
MOV bl,#0x00
CLEAR:
STOSW
INC BL
JNZ CLEAR
mov bx,#compiling mov bx,#compiling
mov ah,#0x02 mov ah,#0x02
print2: print2:
mov dl,[bx] mov dl,[bx]
cmp dl,#0
je exit
int #0x21 int #0x21
inc bx inc bx
cmp dl,#0 jmp print2
jne print2 exit:
MOV SI,#prog MOV SI,#prog
MOV DI,#output_program MOV DI,#0x0700
;CL: write concat CH: move concat ;CL: write concat CH: move concat
MOV CX,#0 MOV CX,#0
JMP COMPILE ; Moving some functions above the main switch to make shot jumps work 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 AL,#0xF4 ; hlt
MOV [DI],AL MOV [DI],AL
MOV BX,#DATA ; From 0x100 its free but i'll do 0x200 in case it start writing earlier
MOV AX,#output_program MOV BX,#0x0200
MOV AX,#0x0700
JMP AX JMP AX
;;;;;;;;; . ;;;;;;;;; ;;;;;;;;; . ;;;;;;;;;
@ -248,18 +261,19 @@ MOV AL,#0x43 ; inc %bx
STOSB STOSB
JMP MOVES_FLUSHED JMP MOVES_FLUSHED
MOVES_ONE_LEFT: MOVES_ONE_LEFT:
MOV AL,#0x4b ; dec %bx MOV AL,#0x4b ; dec %bx
STOSB STOSB
JMP MOVES_FLUSHED JMP MOVES_FLUSHED
MOVES_FLUSHED: MOVES_FLUSHED:
MOV CH,#0 MOV CH,#0
RET RET
bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n'
compiling: .ASCII 'Compiling...\0'
compiled: .ASCII '\rCompiled! \n' compiled: .ASCII '\rCompiled! \n'
DATA: .BLKB 560 compiling: .ASCII 'Compiling...\0'
.BLKB 200 bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n'
STACK: .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 mov sp,#STACK
call INIT_INT_VECT_TABLE
INCLUDE brainfuck_interpreter_v0.asm INCLUDE brainfuck_interpreter_v0.asm
.BLKB 200 .BLKB 200
STACK: STACK:
INCLUDE dos_layer.asm
prog: prog:
INCLUDE hello_9086.bf.asm INCLUDE hello_9086.bf.asm
.ORG 0xFFF0 .ORG 0xFFF0
MOV AX,#0x0100 MOV AX,#0xF000
JMP AX JMP AX

View File

@ -2,7 +2,7 @@
; ;
; This file is part of the 9086 project. ; 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 ; 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 ; it under the terms of the GNU General Public License as published by

View File

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

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: PRINT_INT_HANDLE:
push AX push AX
CMP AH,#0x02 CMP AH,#0x02
@ -14,3 +10,15 @@ MOV AL,DL
out byte #0xA5 out byte #0xA5
POP AX POP AX
iret 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

View File

@ -1,8 +1,8 @@
INCLUDE dos_layer.asm
org 0x100 org 0xF000
mov sp,#STACK mov sp,#STACK
call INIT_INT_VECT_TABLE
MOV AX,#0x1 MOV AX,#0x1
MOV BX,#0x1 MOV BX,#0x1
@ -26,6 +26,7 @@ MOV DL,#0x0a
INT #0x21 INT #0x21
hlt hlt
INCLUDE dos_layer.asm
.BLKB 200 .BLKB 200
@ -33,6 +34,6 @@ STACK:
INCLUDE helpers.asm INCLUDE helpers.asm
.ORG 0xFFF0 .ORG 0xFFF0
MOV AX,#0x0100 MOV AX,#0xF000
JMP AX JMP AX

View File

@ -1,11 +1,11 @@
INCLUDE dos_layer.asm
.org 0x100 .org 0xF000
mov sp,#STACK mov sp,#STACK
MOV SI,#DATA MOV SI,#DATA
call INIT_INT_VECT_TABLE
GNOME_SORT: GNOME_SORT:
CMP SI,#DATA+31 CMP SI,#DATA+23
JZ GNOMED JZ GNOMED
MOV AX,[SI] MOV AX,[SI]
INC SI INC SI
@ -29,7 +29,7 @@ PRINT_LOOP:
MOV AL,[SI] MOV AL,[SI]
call PRINT_0_8_HEX call PRINT_0_8_HEX
INC SI INC SI
CMP SI,#DATA+32 CMP SI,#DATA+24
JNZ PRINT_LOOP JNZ PRINT_LOOP
MOV AH,#0x02 MOV AH,#0x02
@ -37,11 +37,11 @@ MOV DL,#0x0a
INT #0x21 INT #0x21
hlt hlt
INCLUDE dos_layer.asm
DATA: DB 0x51, 0x17, 0x37, 0x5d, 0x06, 0x3f, 0x51, 0x8b DATA: DB 0x51, 0x17, 0x37, 0x5d, 0x06, 0x3f, 0x51, 0x8b
DB 0xa5, 0x33, 0x54, 0xdf, 0xae, 0xee, 0x3a, 0x18 DB 0xa5, 0x33, 0x54, 0xdf, 0xae, 0xee, 0x3a, 0x18
DB 0xe9, 0xdb, 0x1f, 0x21, 0x44, 0x4f, 0x99, 0x09 DB 0xe9, 0xdb, 0x1f, 0x21, 0x44, 0x4f, 0x99, 0x09
DB 0x2a, 0x23, 0x82, 0x4f, 0x52, 0xf1, 0xdc, 0x0b
.BLKB 200 .BLKB 200
STACK: STACK:
@ -49,6 +49,8 @@ STACK:
INCLUDE helpers.asm INCLUDE helpers.asm
.ORG 0xFFF0 .ORG 0xFFF0
MOV AX,#0x0100 MOV AX,#0xF000
JMP AX JMP AX
.ORG 0xFFFF
DB 0x00 ;Make sure a full 64KiB image

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

@ -1,4 +1,4 @@
org 0x100 org 0xF000
inc ax inc ax
inc bx inc bx
inc ax inc ax
@ -102,5 +102,5 @@ inc bx
hlt hlt
.ORG 0xFFF0 .ORG 0xFFF0
MOV AX,#0x0100 MOV AX,#0xF000
JMP AX JMP AX

View File

@ -1,26 +1,59 @@
.PRECIOUS:${BOOT_CODE} .PRECIOUS:${BOOT_CODE}
########## BUILD OPTIONS ##########
QUIET=1 QUIET=1
# QUIET: 1=clean, non-verbose output # QUIET: 1=clean, non-verbose output
# 2=normal make output # 2=normal make output
####### SIMULATION OPTIONS ########
SIM=VERILATOR SIM=VERILATOR
# SIM: VERILATOR: use Verilator # SIM: VERILATOR: use Verilator
# ICARUS: use Icarus Verilog # ICARUS: use Icarus Verilog
NUMACTL=#numactl -m 0 -C 0,1 -- NUMACTL=#numactl -m 0 -C 0,1 --
VERSION="v0.2.0" ######## SYNTHESIS OPTIONS ########
COMMIT=$(shell git log --pretty=format:'%H' -1 |cat)
# 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" ifeq "${QUIET}" "1"
QUIET_AS = @echo ' AS '$@; QUIET_AS = @echo ' AS '${PRINT_PATH_PREFIX}$@;
QUIET_CC = @echo ' CC '$@;
QUIET_VVP = @echo ' VVP '$@; QUIET_VVP = @echo ' VVP '${PRINT_PATH_PREFIX}$@;
QUIET_IVERILOG = @echo ' IVERILOG '$@; QUIET_IVERILOG = @echo ' IVERILOG '${PRINT_PATH_PREFIX}$@;
QUIET_VERILATOR = @echo ' VERILATOR '$@;
QUIET_CLEAN = @printf ' CLEAN %s\n' $1; QUIET_VERILATOR = @echo ' VERILATOR '${PRINT_PATH_PREFIX}$@;
QUIET_VERILATOR_RUN = @printf ' %s %s\n' $1 $2; 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 = @ Q = @
MAKEOPTS=--no-print-directory MAKEOPTS=--no-print-directory
.SILENT: .SILENT:
@ -35,12 +68,20 @@ wave: $(subst .txt,.wave,${BOOT_CODE})
disas: $(subst .txt,.disas,${BOOT_CODE}) disas: $(subst .txt,.disas,${BOOT_CODE})
# Assembling code # Assembling code
%.txt:%.bin %.stxt: %.bin
${Q}dd if=/dev/zero bs=1 count=65536 of="$(subst .bin,.stage,$<)" status=none ${Q}dd if=/dev/zero bs=1 count=2048 of="$(subst .bin,.stage,$<)" status=none
${Q}dd if="$<" of="$(subst .bin,.stage,$<)" conv=notrunc,nocreat 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}xxd -ps -c 2 "$(subst .bin,.stage,$<)" > "$@"
${Q}rm "$(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_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" ifeq "${NO_ASM}" "0"
%.bin:%.asm %.bin:%.asm
${QUIET_AS} ${QUIET_AS}

View File

@ -1 +0,0 @@
,user,localhost,24.10.2023 00:59,file:///home/user/.config/libreoffice/4;

View File

@ -1,6 +1,6 @@
# This file is part of the 9086 project. # 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 # 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 # 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 # You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>. # 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 biu.v execute.v SOURCES=processor.v memory.v registers.v alu.v decoder.v general.v biu.v execute.v
EVENT_SIM_TESTBENCH=testbench.v
VERILATOR_TESTBENCH=testbench.cpp
INCLUDES=exec_state_def.v alu_header.v config.v ucode_header.v error_header.v INCLUDES=exec_state_def.v alu_header.v config.v ucode_header.v error_header.v
SYSTEM_VVP=system.vvp
VERILATOR_BIN=obj_dir/Vsystem
BOOT_CODE=boot_code.txt
GTKWSAVE=../gtkwave_savefile.gtkw
MICROCODE=ucode.txt 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 NO_ASM=0
include ../common.mk 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 #build options
VERILATOR_OPTS += --cc --exe VERILATOR_OPTS += --cc --exe
@ -36,26 +64,114 @@ VERILATOR_OPTS += --cc --exe
VERILATOR_OPTS += --trace-fst --threads 1 --autoflush VERILATOR_OPTS += --trace-fst --threads 1 --autoflush
#linter options #linter options
VERILATOR_OPTS += -Wall --Wno-DECLFILENAME -Wno-SYNCASYNCNET -Wno-MULTIDRIVEN VERILATOR_OPTS += -Wall --Wno-DECLFILENAME
#optimisation options #optimisation options
VERILATOR_OPTS += -x-assign fast --x-initial fast VERILATOR_OPTS += -x-assign fast --x-initial fast
#For testing use: #For testing use:
#VERILATOR_OPTS += -x-assign unique --x-initial unique #VERILATOR_OPTS += -x-assign unique --x-initial unique
################################################################################
#### SIMULATION RECIPES ####
################################################################################
# COMPILING # COMPILING
${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH} ${SYSTEM_VVP} : ${SIMULATED_SOURCES} ${EVENT_SIM_TESTBENCH}
${QUIET_IVERILOG} ${QUIET_IVERILOG}
${Q}iverilog -g2012 -D CALCULATE_IPC -D OTUPUT_JSON_STATISTICS -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 ${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} ${QUIET_VERILATOR}
${Q}verilator -DCALCULATE_IPC -DOTUPUT_JSON_STATISTICS ${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 .PHONY: clean
clean: clean:
$(call QUIET_CLEAN,system) $(call QUIET_CLEAN,system)
${Q}rm -rf ${SYSTEM_VVP} *.fst boot_code.txt boot_code.bin *memdump *memdumptxt obj_dir *json ${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. 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 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 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_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: {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_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_AND: begin C_FLAG=0;OUT[7:0]=A[7:0]&B[7:0]; end
`ALU_OP_OR: begin C_FLAG=0;OUT=A|B; 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=A^B; 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=A<<B; end `ALU_OP_SHIFT_LEFT: begin C_FLAG=(A&16'h80)==16'h80;OUT[7:0]=A[7:0]<<B; end
endcase endcase
end end
end end

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by

View File

@ -3,7 +3,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -45,39 +45,40 @@ module BIU (
/**************** OUTSIDE WORLD ****************/ /**************** OUTSIDE WORLD ****************/
/* */ ,output wire [19:0] external_address_bus /* */ ,output wire [19:0] external_address_bus
/* */ ,inout [15:0] external_data_bus,output reg read, output reg write,output reg BHE,output reg IOMEM /* */ ,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 TO DE ****************/
/* */ ,output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION /* */ ,output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION
/* */ ,output reg VALID_DATA, output reg DATA_DIR /* */ ,output reg VALID_DATA
/**************** INPUT FROM DE ****************/ /**************** INPUT FROM DE ****************/
,input Wbit, input MEM_OR_IO, input valid_instruction_ack ,input Wbit, input MEM_OR_IO, input valid_instruction_ack
/**************** INPUT FROM EX ****************/ /**************** INPUT FROM EX ****************/
/* */ ,input jump_req, input write_request, input read_request /* */ ,input jump_req, input write_request, input read_request
/* */ ,input[15:0] ADDRESS_INPUT /* */ ,input[15:0] ADDRESS_INPUT, input [15:0] DATA_EX_WRITE
/************ BIDIRECTIONAL WITH EX ************/ /**************** OUTPUT TO EX *****************/
/* */ ,inout [15:0] DATA /* */ ,output [15:0] DATA_EX_READ
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
/***************** STATISTICS *****************/ /***************** STATISTICS *****************/
/* */ ,output wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE_STAT, output wire VALID_INSTRUCTION_STAT /* */ ,output wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE_STAT, output wire VALID_INSTRUCTION_STAT
`endif `endif
); );
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
assign FIFO_SIZE_STAT = FIFO_SIZE; 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); 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 `endif
reg [15:0] data_bus_output_register; reg [15:0] data_bus_output_register;
assign external_data_bus=read?data_bus_output_register:16'hz; assign external_data_bus_write=data_bus_output_register; //TODO: should we rename?
reg [15:0] DATA_OUT; reg [15:0] DATA_OUT;
assign DATA=DATA_DIR ? 16'hz:DATA_OUT; assign DATA_EX_READ=DATA_OUT; //TODO should we rename?
`define FIFO_SIZE_BYTES $rtoi($pow(2,`L1_CACHE_SIZE)) `define FIFO_SIZE_BYTES $rtoi($pow(2,`L1_CACHE_SIZE))
@ -89,21 +90,6 @@ wire [`L1_CACHE_SIZE-1:0] FIFO_SIZE = FIFO_end-FIFO_start;
reg [3:0] biu_state; reg [3:0] biu_state;
reg sane; reg sane;
always @(negedge reset) begin
biu_state <= `BIU_HALT;
write <= 1;
sane <= 0;
end
always @(posedge reset) begin
biu_state <= `BIU_RESET1;
/* verilator lint_off BLKSEQ */
FIFO_start = `L1_CACHE_SIZE'b0;
FIFO_end = `L1_CACHE_SIZE'b0;
/* verilator lint_on BLKSEQ */
end
reg jump_req_latch;
reg func; reg func;
reg [19:0]INSTRUCTION_ADDRESS; reg [19:0]INSTRUCTION_ADDRESS;
reg [19:0]DATA_ADDRESS; reg [19:0]DATA_ADDRESS;
@ -111,13 +97,25 @@ reg [19:0]DATA_ADDRESS;
assign external_address_bus= func ? INSTRUCTION_ADDRESS : DATA_ADDRESS ; assign external_address_bus= func ? INSTRUCTION_ADDRESS : DATA_ADDRESS ;
always @(posedge clock) begin always @(posedge clock) begin
if ( jump_req_latch ) begin if ( reset == 0 ) begin
INSTRUCTION_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; 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; INSTRUCTION_LOCATION <= ADDRESS_INPUT;
func <= 1; func <= 1;
jump_req_latch <= 0;
if (biu_state==`BIU_READ) if (biu_state==`BIU_READ)
biu_state <= `BIU_NEXT_ACTION; 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 end else begin
case(biu_state) case(biu_state)
`BIU_HALT: begin `BIU_HALT: begin
@ -125,18 +123,14 @@ always @(posedge clock) begin
`BIU_NEXT_ACTION: begin /* decide if we can read, if we are full or if we need to do something else */ `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 if (write_request) begin
func<=0; func<=0;
DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT };
DATA_DIR <= 1 ;
IOMEM <= MEM_OR_IO; 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) ; biu_state <= (Wbit==0) ? `BIU_PUT_BYTE : (ADDRESS_INPUT[0:0]?`BIU_PUT_UNALIGNED_16BIT_DATA:`BIU_PUT_ALIGNED_16BIT_DATA) ;
INSTRUCTION_ADDRESS <= {4'b0,INSTRUCTION_LOCATION} ; INSTRUCTION_ADDRESS <= {4'hF,INSTRUCTION_LOCATION} ;
/* verilator lint_off BLKSEQ */ FIFO_end<=FIFO_start;
FIFO_end=FIFO_start;
/* verilator lint_on BLKSEQ */
end else if ( read_request ) begin end else if ( read_request ) begin
func<=0; func<=0;
DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT };
DATA_DIR <= 0;
IOMEM <= MEM_OR_IO; IOMEM <= MEM_OR_IO;
read <= 0; read <= 0;
BHE <= 0; BHE <= 0;
@ -161,23 +155,17 @@ always @(posedge clock) begin
/*************** INSTRUCTION FIFO READ ***************/ /*************** INSTRUCTION FIFO READ ***************/
`BIU_READ: begin `BIU_READ: begin
if(INSTRUCTION_ADDRESS[0:0]==0 && FIFO_SIZE<{{(`L1_CACHE_SIZE-1){1'b1}},1'b0})begin if(INSTRUCTION_ADDRESS[0:0]==0 && FIFO_SIZE<{{(`L1_CACHE_SIZE-1){1'b1}},1'b0})begin
/* verilator lint_off BLKSEQ */ INPUT_FIFO[FIFO_end] <= external_data_bus_read[7:0];
INPUT_FIFO[FIFO_end] = external_data_bus[7:0]; INPUT_FIFO[FIFO_end+`L1_CACHE_SIZE'd1] <= external_data_bus_read[15:8];
INPUT_FIFO[FIFO_end+`L1_CACHE_SIZE'd1] = external_data_bus[15:8]; FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd2;
FIFO_end = FIFO_end+`L1_CACHE_SIZE'd2;
/* verilator lint_on BLKSEQ */
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd2; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd2;
end else if(INSTRUCTION_ADDRESS[0:0]==0)begin end else if(INSTRUCTION_ADDRESS[0:0]==0)begin
/* verilator lint_off BLKSEQ */ INPUT_FIFO[FIFO_end] <= external_data_bus_read[7:0];
INPUT_FIFO[FIFO_end] = external_data_bus[7:0]; FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd1;
FIFO_end = FIFO_end+`L1_CACHE_SIZE'd1;
/* verilator lint_on BLKSEQ */
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1;
end else begin end else begin
/* verilator lint_off BLKSEQ */ INPUT_FIFO[FIFO_end] <= external_data_bus_read[15:8];
INPUT_FIFO[FIFO_end] = external_data_bus[15:8]; FIFO_end <= FIFO_end+`L1_CACHE_SIZE'd1;
FIFO_end = FIFO_end+`L1_CACHE_SIZE'd1;
/* verilator lint_on BLKSEQ */
INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1; INSTRUCTION_ADDRESS <= INSTRUCTION_ADDRESS+20'd1;
end end
biu_state <= `BIU_NEXT_ACTION; biu_state <= `BIU_NEXT_ACTION;
@ -185,13 +173,12 @@ always @(posedge clock) begin
end end
/*************** DATA WRITE ***************/ /*************** DATA WRITE ***************/
//TODO TODO TODO flush fifo, self modifying code
`BIU_PUT_UNALIGNED_16BIT_DATA:begin `BIU_PUT_UNALIGNED_16BIT_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Writing 16bit %04x at %04x",DATA,DATA_ADDRESS); $display("Writing 16bit %04x at %04x",DATA_EX_WRITE,DATA_ADDRESS);
`endif `endif
BHE <= 0; BHE <= 0;
data_bus_output_register <= {DATA[7:0],DATA[15:8]}; data_bus_output_register <= {DATA_EX_WRITE[7:0],DATA_EX_WRITE[15:8]};
write <= 0; write <= 0;
biu_state <= `BIU_PUT_UNALIGNED_PREP_NEXT2; biu_state <= `BIU_PUT_UNALIGNED_PREP_NEXT2;
end end
@ -203,22 +190,22 @@ always @(posedge clock) begin
end end
`BIU_PUT_ALIGNED_16BIT_DATA:begin `BIU_PUT_ALIGNED_16BIT_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Writing 16bit %04x at %04x",DATA,DATA_ADDRESS); $display("Writing 16bit %04x at %04x",DATA_EX_WRTIE,DATA_ADDRESS);
`endif `endif
data_bus_output_register <= {DATA[15:8],DATA[7:0]}; data_bus_output_register <= {DATA_EX_WRITE[15:8],DATA_EX_WRITE[7:0]};
write <= 0; write <= 0;
biu_state <= `BIU_WRITE_RELEASE; biu_state <= `BIU_WRITE_RELEASE;
end end
`BIU_PUT_BYTE:begin `BIU_PUT_BYTE:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Writing 8bit %02x at %04x",DATA[7:0],DATA_ADDRESS); $display("Writing 8bit %02x at %04x",DATA_EX_WRITE[7:0],DATA_ADDRESS);
`endif `endif
if(ADDRESS_INPUT[0:0]==0) begin if(ADDRESS_INPUT[0:0]==0) begin
BHE <= 1; BHE <= 1;
data_bus_output_register <= {8'b0,DATA[7:0]}; data_bus_output_register <= {8'b0,DATA_EX_WRITE[7:0]};
end else begin end else begin
BHE <= 0; BHE <= 0;
data_bus_output_register <= {DATA[7:0],8'b0}; data_bus_output_register <= {DATA_EX_WRITE[7:0],8'b0};
end end
write <= 0; write <= 0;
biu_state <= `BIU_WRITE_RELEASE; biu_state <= `BIU_WRITE_RELEASE;
@ -235,7 +222,6 @@ always @(posedge clock) begin
/*************** DATA READ ***************/ /*************** DATA READ ***************/
`define finished_read \ `define finished_read \
DATA_DIR <= 0; \
if ( read_request == 0 ) begin \ if ( read_request == 0 ) begin \
biu_state <= `BIU_NEXT_ACTION;\ biu_state <= `BIU_NEXT_ACTION;\
VALID_DATA <= 0;\ VALID_DATA <= 0;\
@ -244,20 +230,20 @@ always @(posedge clock) begin
`BIU_GET_ALIGNED_DATA:begin `BIU_GET_ALIGNED_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
if(Wbit==1) if(Wbit==1)
$display("Reading 16bit %04x from %04x",external_data_bus,DATA_ADDRESS); $display("Reading 16bit %04x from %04x",external_data_bus_read,DATA_ADDRESS);
else else
$display("Reading 8bit %02x from %04x",external_data_bus[7:0],DATA_ADDRESS); $display("Reading 8bit %02x from %04x",external_data_bus_read[7:0],DATA_ADDRESS);
`endif `endif
DATA_OUT <= (Wbit==1)? external_data_bus : {8'b0,external_data_bus[7:0]} ; DATA_OUT <= (Wbit==1)? external_data_bus_read : {8'b0,external_data_bus_read[7:0]} ;
read <=1; read <=1;
`finished_read `finished_read
end end
`BIU_GET_UNALIGNED_DATA:begin `BIU_GET_UNALIGNED_DATA:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
if(Wbit==0) if(Wbit==0)
$display("Reading 8bit %02x from %04x",external_data_bus[15:8],DATA_ADDRESS); $display("Reading 8bit %02x from %04x",external_data_bus_read[15:8],DATA_ADDRESS);
`endif `endif
DATA_OUT[7:0] <= external_data_bus[15:8]; DATA_OUT[7:0] <= external_data_bus_read[15:8];
read <=1; read <=1;
if(Wbit==1) begin if(Wbit==1) begin
biu_state <= `BIU_GET_SECOND_BYTE; biu_state <= `BIU_GET_SECOND_BYTE;
@ -272,9 +258,9 @@ always @(posedge clock) begin
end end
`BIU_GET_SECOND_BYTE1:begin `BIU_GET_SECOND_BYTE1:begin
`ifdef DEBUG_DATA_READ_WRITES `ifdef DEBUG_DATA_READ_WRITES
$display("Reading 16bit %02x from %04x",{external_data_bus[7:0],DATA_OUT[7:0]},DATA_ADDRESS-1);//read started a byte earlier $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 `endif
DATA_OUT[15:8] <= external_data_bus[7:0]; DATA_OUT[15:8] <= external_data_bus_read[7:0];
`finished_read `finished_read
read <=1; read <=1;
end end
@ -285,15 +271,12 @@ always @(posedge clock) begin
VALID_DATA <= 0; VALID_DATA <= 0;
end end
`BIU_RESET2: begin `BIU_RESET2: begin
/* verilator lint_off BLKSEQ */ FIFO_start <= `L1_CACHE_SIZE'b0;
FIFO_start = `L1_CACHE_SIZE'b0; FIFO_end <= `L1_CACHE_SIZE'b0;
FIFO_end = `L1_CACHE_SIZE'b0;
/* verilator lint_on BLKSEQ */
biu_state <= `BIU_NEXT_ACTION; biu_state <= `BIU_NEXT_ACTION;
INSTRUCTION_ADDRESS <= 20'h0FFF0; INSTRUCTION_ADDRESS <= 20'hFFFF0;
INSTRUCTION_LOCATION <= 16'hFFF0; INSTRUCTION_LOCATION <= 16'hFFF0;
VALID_DATA <= 0; VALID_DATA <= 0;
DATA_DIR <= 0;
sane<=1; sane<=1;
end end
default: begin default: begin
@ -303,60 +286,39 @@ always @(posedge clock) begin
end end
end end
wire [2:0] Isize; /* update VALID_INSTRUCTION and INSTRUCTION */
InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize); always @( posedge clock) begin
`ifdef INCLUDE_EARLY_CALC_CIRUIT if(jump_req==1)begin
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
always @( valid_instruction_ack ) begin
/* verilator lint_off BLKSEQ */
FIFO_start = FIFO_start + {{`L1_CACHE_SIZE-3{1'b0}},Isize};
/* verilator lint_on BLKSEQ */
INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {13'd0,Isize};
end
always @( FIFO_start or FIFO_end ) begin
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; VALID_INSTRUCTION <= 0;
end else begin end else if(sane==1) begin
VALID_INSTRUCTION <= 0; //if(VALID_INSTRUCTION == 1 ) begin
end // `ifdef DOUBLE_INSTRUCTION_LOAD
`else // if(FIFO_SIZE>`L1_CACHE_SIZE'd3+{{`L1_CACHE_SIZE-3{1'b0}},Isize})begin
VALID_INSTRUCTION <= 0; // if((fifoIsize2==2) && (FIFO_SIZE > `L1_CACHE_SIZE'd1+{{`L1_CACHE_SIZE-3{1'b0}},fifoIsize}))begin
`endif // VALID_INSTRUCTION <= 1;
end else begin // 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]); //$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 `ifdef EARLY_VALID_INSTRUCTION
if(FIFO_start==FIFO_end) begin if(FIFO_start==FIFO_end) begin
@ -383,10 +345,11 @@ always @( FIFO_start or FIFO_end ) begin
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1]; INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2]; INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3]; INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3];
end end else
VALID_INSTRUCTION <= 0;
`else `else
if(FIFO_start==FIFO_end) begin if(FIFO_start==FIFO_end) begin
/*TODO: Same as on the first statment on the other side of the `ifdef */ /*TODO: Same as on the first statement on the other side of the `ifdef */
VALID_INSTRUCTION <= 0; VALID_INSTRUCTION <= 0;
end else if(FIFO_SIZE>`L1_CACHE_SIZE'd3)begin end else if(FIFO_SIZE>`L1_CACHE_SIZE'd3)begin
VALID_INSTRUCTION <= 1; VALID_INSTRUCTION <= 1;
@ -394,19 +357,29 @@ always @( FIFO_start or FIFO_end ) begin
INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1]; INSTRUCTION[23:16] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1];
INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2]; INSTRUCTION[15: 8] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd2];
INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3]; INSTRUCTION[ 7: 0] <= INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd3];
end end else
VALID_INSTRUCTION <= 0;
`endif `endif
end //end
end end
end end
always @( posedge jump_req ) begin wire [2:0] Isize;
/* verilator lint_off BLKSEQ */ InstrSize InstrSize({INSTRUCTION[31:24],INSTRUCTION[21:19]},Isize);
FIFO_start = FIFO_end ;
/* verilator lint_on BLKSEQ */ `ifdef INCLUDE_EARLY_CALC_CIRCUIT
jump_req_latch <= 1; wire [2:0] fifoIsize;
DATA_DIR <= 1; wire Isit1;
VALID_INSTRUCTION <= 0; InstrSize fifoInstrSize({INPUT_FIFO[FIFO_start][7:0],INPUT_FIFO[FIFO_start+`L1_CACHE_SIZE'd1][5:3]},fifoIsize);
end 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 endmodule

View File

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

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@
/** OUTPUT **/ /** OUTPUT **/
/* These are usually set at build time*/ /* These are usually set at build time*/
//`define CALCULATE_IPC //`define CALCULATE_IPC
//`define OTUPUT_JSON_STATISTICS //`define OUTPUT_JSON_STATISTICS
/** Optimisations **/ /** Optimisations **/
@ -34,8 +34,10 @@
* for the maximum instruction size worth of bytes */ * for the maximum instruction size worth of bytes */
`define EARLY_VALID_INSTRUCTION `define EARLY_VALID_INSTRUCTION
/*********** CURRENTLY DOESN'T WORK *************/
/* Enables the ability in BIU to pre-decode two instructions, one after the other in memory*/ /* Enables the ability in BIU to pre-decode two instructions, one after the other in memory*/
`define DOUBLE_INSTRUCTION_LOAD //`define DOUBLE_INSTRUCTION_LOAD
/************************************************/
/* Size is in powers of two with minimal 3. /* Size is in powers of two with minimal 3.
* 3 : 8 Bytes * 3 : 8 Bytes
@ -45,10 +47,21 @@
`define L1_CACHE_SIZE 4 `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 **********/ /********** 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 OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
`define CALCULATE_IPC `define CALCULATE_IPC
`endif `endif
@ -58,12 +71,12 @@
`endif `endif
`ifdef EARLY_VALID_INSTRUCTION `ifdef EARLY_VALID_INSTRUCTION
`define INCLUDE_EARLY_CALC_CIRUIT `define INCLUDE_EARLY_CALC_CIRCUIT
`define EARLY_VALID_INSTRUCTION_ 1 `define EARLY_VALID_INSTRUCTION_ 1
`else `else
`define EARLY_VALID_INSTRUCTION_ 0 `define EARLY_VALID_INSTRUCTION_ 0
`endif `endif
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
`define INCLUDE_EARLY_CALC_CIRUIT `define INCLUDE_EARLY_CALC_CIRCUIT
`endif `endif

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -62,7 +62,9 @@ module decoder(
reg SIMPLE_MICRO; /* use simple decodings (=0) or microcode data (=1) */ reg SIMPLE_MICRO; /* use simple decodings (=0) or microcode data (=1) */
wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry; wire [`UCODE_ADDR_BITS-1:0] ucode_seq_addr_entry;
reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr; reg [`UCODE_ADDR_BITS-1:0] ucode_seq_addr;
/* verilator lint_off UNUSEDSIGNAL */
wire DEPENDS_ON_PREVIOUS; wire DEPENDS_ON_PREVIOUS;
/* verilator lint_on UNUSEDSIGNAL */
wire set_params; wire set_params;
wire MEM_OR_IO, HALT,Wbit,memio_address_select; wire MEM_OR_IO, HALT,Wbit,memio_address_select;
@ -74,7 +76,7 @@ wire [`EXEC_STATE_BITS-1:0] next_state;
wire [`ERROR_BITS-1:0] ERROR; wire [`ERROR_BITS-1:0] ERROR;
instruction_decode instruction_decode( instruction_decode instruction_decode(
/* INPUT */ IF2DE_INSTRUCTION,{8'h0,EX2DE_FLAGS} /* INPUT */ IF2DE_INSTRUCTION,{8'h0,EX2DE_FLAGS}, clock
/* MICROCODE */ ,ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr /* MICROCODE */ ,ucode_seq_addr_entry,SIMPLE_MICRO,ucode_seq_addr
/* OUTPUT */ ,DEPENDS_ON_PREVIOUS, set_params, MEM_OR_IO,ERROR, HALT /* OUTPUT */ ,DEPENDS_ON_PREVIOUS, set_params, MEM_OR_IO,ERROR, HALT
@ -89,59 +91,32 @@ instruction_decode instruction_decode(
/* */ ,reg_write_addr, reg_read_port2_addr, reg_read_port1_addr /* */ ,reg_write_addr, reg_read_port2_addr, reg_read_port1_addr
); );
reg [`DE_STATE_BITS-1:0] de_state;
always @(negedge reset) begin
de_state <= `DE_HALT; //TODO: race condition ??
`ifdef CALCULATE_IPC
new_instruction<=0;
`endif
valid_exec_data<=0;
instant_response <= 0;
stalled_response <= 0;
end
always @(posedge reset) begin
de_state <= `DE_STATE_ENTRY;
/* need early init */
ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
SIMPLE_MICRO <= 0;
owe_set_init <= 0;
set_initial_values<=0;
wait_exec<=0;
first_ucode <= 0;
HALT_LATCHED <= 0;
ERROR_LATCHED <= `ERROR_BITS'h0;
VALID_INSTRUCTION_ACK <= 0;
end
wire [2:0] instr_end; wire [2:0] instr_end;
InstrSize InstrSize({IF2DE_INSTRUCTION[31:24],IF2DE_INSTRUCTION[21:19]},instr_end); InstrSize InstrSize({IF2DE_INSTRUCTION[31:24],IF2DE_INSTRUCTION[21:19]},instr_end);
reg owe_set_init; reg owe_set_init;
//TODO: Why do we need to make a local copy on a register for the code inside the always @(next_state) to read it? reg [1:0] wait_;
// For some reason the raw VALID_INSTRUCTION signal reads always 1 and it has something to do with the block
// being triggered by next_exec
reg VALID_INSTRUCTION_lc;
always @(VALID_INSTRUCTION)begin VALID_INSTRUCTION_lc<=VALID_INSTRUCTION; end
reg instant_response, stalled_response; always @(posedge clock)begin
reg wait_exec; if(reset==0)begin
`ifdef CALCULATE_IPC
always @(next_exec) begin new_instruction<=0;
de_state<=`DE_STATE_ENTRY; `endif
if ( VALID_INSTRUCTION_lc == 1 && DEPENDS_ON_PREVIOUS == 0 && ucode_seq_addr_entry==`UCODE_NO_INSTRUCTION) begin valid_exec_data<=0;
instant_response <= !instant_response; ucode_seq_addr <= `UCODE_NO_INSTRUCTION;
SIMPLE_MICRO <= 0;
owe_set_init <= 0;
set_initial_values<=0;
first_ucode <= 0;
HALT_LATCHED <= 0;
ERROR_LATCHED <= `ERROR_BITS'h0;
VALID_INSTRUCTION_ACK <= 0;
wait_<=0;
end else begin end else begin
wait_exec<=0; if(wait_==2) begin
end
end
reg first_ucode;
always @(instant_response or stalled_response) begin
//`define LATCH(VAR) VAR_LATCHED <= VAR; //TODO would this work? //`define LATCH(VAR) VAR_LATCHED <= VAR; //TODO would this work?
IN_MOD_LATCHED <= IN_MOD; IN_MOD_LATCHED <= IN_MOD;
OUT_MOD_LATCHED <= OUT_MOD; OUT_MOD_LATCHED <= OUT_MOD;
@ -166,8 +141,9 @@ always @(instant_response or stalled_response) begin
ucode_seq_addr <= ucode_seq_addr_entry; ucode_seq_addr <= ucode_seq_addr_entry;
SIMPLE_MICRO <= 1; SIMPLE_MICRO <= 1;
first_ucode <= 1; first_ucode <= 1;
set_initial_values <= !set_initial_values; set_initial_values <= 1;
/*keep de_state the same and rerun decode this time with all the data from the microcode rom*/ valid_exec_data <= 0;
wait_<=1;
end else begin end else begin
if(SIMPLE_MICRO==0||first_ucode==1||owe_set_init==1)begin if(SIMPLE_MICRO==0||first_ucode==1||owe_set_init==1)begin
first_ucode <= 0; first_ucode <= 0;
@ -180,13 +156,14 @@ always @(instant_response or stalled_response) begin
`endif `endif
owe_set_init<=0; owe_set_init<=0;
ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end}; ProgCount <= INSTRUCTION_LOCATION+{12'b0,instr_end};
VALID_INSTRUCTION_ACK <= !VALID_INSTRUCTION_ACK; VALID_INSTRUCTION_ACK <= 1;
end end
if(set_params)begin if(set_params)begin
set_initial_values <= !set_initial_values; set_initial_values <= 1;
end end
/* This runs at the start of each execution cycle, with microcode this is more than once per 8086 instruction */ /* This runs at the start of each execution cycle, with microcode this is more than once per 8086 instruction */
valid_exec_data<=!valid_exec_data; valid_exec_data<=1;
wait_<=1;
if( SIMPLE_MICRO == 1 ) begin if( SIMPLE_MICRO == 1 ) begin
ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/ ucode_seq_addr <= ucode_seq_addr_entry; /*Reused for next address*/
if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin if( ucode_seq_addr_entry == `UCODE_NO_INSTRUCTION )begin
@ -194,23 +171,22 @@ always @(instant_response or stalled_response) begin
SIMPLE_MICRO <= 0; SIMPLE_MICRO <= 0;
end end
end end
wait_exec<=1; end
end else if(wait_!=0) begin
set_initial_values <= 0;
wait_<=0;
VALID_INSTRUCTION_ACK<=0;
end else if(next_exec==1'b1)begin
if ( ( VALID_INSTRUCTION == 1 || SIMPLE_MICRO == 1 ) /*&& DEPENDS_ON_PREVIOUS == 0 && ucode_seq_addr_entry==`UCODE_NO_INSTRUCTION*/) begin
wait_<=2;
end else
valid_exec_data<=0;
end else
valid_exec_data<=0;
end end
end end
always @(posedge clock) begin reg first_ucode;
case(de_state)
`DE_STATE_ENTRY:begin
if ( ( VALID_INSTRUCTION==1 || SIMPLE_MICRO == 1 ) && wait_exec==0) begin
stalled_response <= !stalled_response;
end
end
`DE_HALT:begin
end
default:begin
end
endcase
end
endmodule endmodule
@ -224,6 +200,7 @@ module microcode(
); );
initial begin initial begin
`ifndef YOSYS
string ucode_path; string ucode_path;
if($value$plusargs("MICROCODE=%s",ucode_path))begin if($value$plusargs("MICROCODE=%s",ucode_path))begin
$readmemb(ucode_path,ucode_rom,0,`UCODE_SIZE-1); $readmemb(ucode_path,ucode_rom,0,`UCODE_SIZE-1);
@ -231,6 +208,10 @@ initial begin
$display("Please supply microcode rom file as a runtime vvp argument +MICROCODE=<path>"); $display("Please supply microcode rom file as a runtime vvp argument +MICROCODE=<path>");
$finish; $finish;
end end
`else
//TODO: don't have it hard coded
$readmemb("simplified_ucode.txt",ucode_rom,0,`UCODE_SIZE-1);
`endif
end end
reg [`UCODE_DATA_BITS-1:0] ucode_rom [ 0:`UCODE_SIZE-1 ]; reg [`UCODE_DATA_BITS-1:0] ucode_rom [ 0:`UCODE_SIZE-1 ];
@ -240,7 +221,9 @@ assign DATA=ucode_rom[ADDR];
endmodule endmodule
module instruction_decode( module instruction_decode(
/* INPUTS */ input wire [31:0] INSTRUCTION,input wire [15:0] FLAGS /* verilator lint_off UNUSEDSIGNAL */
/* INPUTS */ input wire [31:0] INSTRUCTION,input wire [15:0] FLAGS,input clock
/* verilator lint_on UNUSEDSIGNAL */
/* MICROCODE */ ,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input /* MICROCODE */ ,output reg [`UCODE_ADDR_BITS-1:0] seq_addr_entry, input wire SIMPLE_MICRO, input wire [`UCODE_ADDR_BITS-1:0] seq_addr_input
/* OUTPUT */ ,output reg DEPENDS_ON_PREVIOUS, output reg set_params,output reg MEM_OR_IO, output reg [`ERROR_BITS-1:0] ERROR, output reg HALT /* OUTPUT */ ,output reg DEPENDS_ON_PREVIOUS, output reg set_params,output reg MEM_OR_IO, output reg [`ERROR_BITS-1:0] ERROR, output reg HALT
@ -265,16 +248,10 @@ wire [`UCODE_DATA_BITS-1:0] ucode_data;
microcode ucode(seq_addr_input,ucode_data); microcode ucode(seq_addr_input,ucode_data);
`define invalid_instruction next_state=`EXEC_WAIT;ERROR<=`ERR_UNIMPL_INSTRUCTION;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION; `define invalid_instruction next_state=`EXEC_WAIT;ERROR<=`ERR_UNIMPL_INSTRUCTION;HALT<=0;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION;opcode_size=0;DEPENDS_ON_PREVIOUS<=0;
`define unimpl_addressing_mode next_state=`EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION; `define unimpl_addressing_mode next_state=`EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;HALT<=0;IN_MOD=3'b011;seq_addr_entry<=`UCODE_NO_INSTRUCTION;
`define normal_instruction seq_addr_entry<=`UCODE_NO_INSTRUCTION;ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO<=0;
`define normal_microcoded ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO<=0;
//TODO: A possible optimisation for instruction with 8bit parameter and
//opcode_size=0 would be to set PARAM1 here instead of sending execution over
//to EXEC_DE_LOAD_8_PARAM
`define normal_instruction seq_addr_entry<=`UCODE_NO_INSTRUCTION;ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO=0;
`define normal_microcoded ERROR<=`ERR_NO_ERROR;HALT<=0;MEM_OR_IO=0;
reg [1:0] PARAM_ACTION; reg [1:0] PARAM_ACTION;
`define NO_LOAD 2'b00 `define NO_LOAD 2'b00
@ -287,7 +264,7 @@ reg Sbit,opcode_size;
// then branching off of that instead of the raw bits. otherwise the code // then branching off of that instead of the raw bits. otherwise the code
// would be identical // would be identical
/* verilator lint_off BLKSEQ */ /* verilator lint_off BLKSEQ */
always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin always @( posedge clock ) begin
set_params = 1; set_params = 1;
PARAM_ACTION = `NO_LOAD; PARAM_ACTION = `NO_LOAD;
Sbit=0;//TODO: If no Sbit we assume it's 0,right? Sbit=0;//TODO: If no Sbit we assume it's 0,right?
@ -298,21 +275,22 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
/* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/ /* 0 0 0 0 0 1 0 W | DATA | DATA if W |*/
opcode_size=0; opcode_size=0;
Wbit=INSTRUCTION[24:24]; Wbit=INSTRUCTION[24:24];
Sbit=0;
IN_MOD=3'b011; IN_MOD=3'b011;
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
OUT_MOD=3'b011; OUT_MOD=3'b011;
MEM_OR_IO=0; MEM_OR_IO<=0;
reg_read_port2_addr={Wbit,3'b000}; reg_read_port2_addr<={Wbit,3'b000};
reg_write_addr={Wbit,3'b000}; reg_write_addr<={Wbit,3'b000};
ALU_OP=`ALU_OP_ADD; ALU_OP<=`ALU_OP_ADD;
memio_address_select=0; memio_address_select=0;
if(Wbit) if(Wbit)
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
else else
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
`normal_instruction; `normal_instruction
end end
11'b1000_00??_101, /* SUB */ 11'b1000_00??_101, /* SUB */
11'b1000_00??_000 : /* ADD */ begin 11'b1000_00??_000 : /* ADD */ begin
@ -328,13 +306,13 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
reg_write_addr={Wbit,RM}; reg_write_addr<={Wbit,RM};
end else begin end else begin
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
end end
OUT_MOD=IN_MOD; OUT_MOD=IN_MOD;
MEM_OR_IO=0; MEM_OR_IO<=0;
memio_address_select=0; memio_address_select=0;
case({Sbit,Wbit}) // TODO: Isn't this supposed to be just a LOAD_8? case({Sbit,Wbit}) // TODO: Isn't this supposed to be just a LOAD_8?
2'b00,2'b11:begin 2'b00,2'b11:begin
@ -348,15 +326,15 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
end end
endcase endcase
case(INSTRUCTION[21:19]) case(INSTRUCTION[21:19])
3'b000: ALU_OP=`ALU_OP_ADD; 3'b000: ALU_OP<=`ALU_OP_ADD;
3'b101: ALU_OP=`ALU_OP_SUB_REVERSE; 3'b101: ALU_OP<=`ALU_OP_SUB_REVERSE;
default:begin default:begin
/*Should be impossible*/ /*Should be impossible*/
`invalid_instruction `invalid_instruction
end end
endcase endcase
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
`normal_instruction; `normal_instruction
end end
11'b1000_00??_111 : begin 11'b1000_00??_111 : begin
/* CMP - compare Immediate with register / memory */ /* CMP - compare Immediate with register / memory */
@ -371,13 +349,13 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
end end
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
OUT_MOD=3'b100; OUT_MOD=3'b100;
MEM_OR_IO=0; MEM_OR_IO<=0;
ALU_OP=`ALU_OP_SUB_REVERSE; ALU_OP<=`ALU_OP_SUB_REVERSE;
memio_address_select=0; memio_address_select=0;
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
/*compare register with param*/ /*compare register with param*/
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end else begin end else begin
/*compare register indirect access /*compare register indirect access
@ -391,7 +369,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
else else
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
`normal_instruction; `normal_instruction
end end
11'b1011_????_??? : begin 11'b1011_????_??? : begin
/* MOV - Move Immediate byte to register */ /* MOV - Move Immediate byte to register */
@ -402,16 +380,16 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
OUT_MOD=3'b011; OUT_MOD=3'b011;
MEM_OR_IO=0; MEM_OR_IO<=0;
reg_write_addr={Wbit,INSTRUCTION[26:24]}; reg_write_addr<={Wbit,INSTRUCTION[26:24]};
if(Wbit) if(Wbit)
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
else else
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
PARAM2=0; PARAM2=0;
ALU_OP=`ALU_OP_ADD; ALU_OP<=`ALU_OP_ADD;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -422,15 +400,15 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
RM=INSTRUCTION[18:16]; RM=INSTRUCTION[18:16];
Wbit=INSTRUCTION[24:24]; Wbit=INSTRUCTION[24:24];
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
PARAM1=0; PARAM1<=0;
MEM_OR_IO=0; MEM_OR_IO<=0;
if(INSTRUCTION[25:25] == 1)begin if(INSTRUCTION[25:25] == 1)begin
/* Mem/Reg to reg */ /* Mem/Reg to reg */
IN_MOD={1'b0,INSTRUCTION[23:22]}; IN_MOD={1'b0,INSTRUCTION[23:22]};
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
/*Reg to Reg*/ /*Reg to Reg*/
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end else begin end else begin
/*Mem to Reg*/ /*Mem to Reg*/
@ -438,7 +416,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_MEMIO_READ; next_state=`EXEC_MEMIO_READ;
end end
OUT_MOD=3'b011; OUT_MOD=3'b011;
reg_write_addr={Wbit,INSTRUCTION[21:19]}; reg_write_addr<={Wbit,INSTRUCTION[21:19]};
end else begin end else begin
/* Reg to Mem/Reg */ /* Reg to Mem/Reg */
IN_MOD=3'b011; IN_MOD=3'b011;
@ -446,18 +424,18 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
/*Reg to Reg*/ /*Reg to Reg*/
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_write_addr={Wbit,RM}; reg_write_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end else begin end else begin
/*Reg to Mem*/ /*Reg to Mem*/
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
next_state=`EXEC_DE_LOAD_REG_TO_PARAM; next_state=`EXEC_DE_LOAD_REG_TO_PARAM;
end end
reg_read_port2_addr={Wbit,INSTRUCTION[21:19]}; reg_read_port2_addr<={Wbit,INSTRUCTION[21:19]};
end end
ALU_OP=`ALU_OP_ADD; ALU_OP<=`ALU_OP_ADD;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -471,17 +449,17 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b01; in_alu_sel1=2'b01;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
OUT_MOD=3'b011; OUT_MOD=3'b011;
MEM_OR_IO=0; MEM_OR_IO<=0;
IN_MOD=3'b011; IN_MOD=3'b011;
PARAM2=1; PARAM2=1;
reg_read_port1_addr={1'b1,INSTRUCTION[26:24]}; reg_read_port1_addr<={1'b1,INSTRUCTION[26:24]};
reg_write_addr={1'b1,INSTRUCTION[26:24]}; reg_write_addr<={1'b1,INSTRUCTION[26:24]};
if(INSTRUCTION[27:27]==0) if(INSTRUCTION[27:27]==0)
ALU_OP=`ALU_OP_ADD; ALU_OP<=`ALU_OP_ADD;
else else
ALU_OP=`ALU_OP_SUB; ALU_OP<=`ALU_OP_SUB;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -496,33 +474,41 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
RM=INSTRUCTION[18:16]; RM=INSTRUCTION[18:16];
in_alu_sel2=(IN_MOD==3'b011)? 2'b01 : 2'b00; in_alu_sel2=(IN_MOD==3'b011)? 2'b01 : 2'b00;
in_alu_sel1=2'b00;/* number 1 */ in_alu_sel1=2'b00;/* number 1 */
PARAM1=1; PARAM1<=16'd1;
OUT_MOD=IN_MOD; OUT_MOD=IN_MOD;
MEM_OR_IO=0; MEM_OR_IO<=0;
/*in case IN_MOD=011 */ /*in case IN_MOD=011 */
reg_read_port2_addr={1'b0,RM}; reg_read_port2_addr<={1'b0,RM};
reg_write_addr={1'b0,RM}; reg_write_addr<={1'b0,RM};
ALU_OP=(INSTRUCTION[19:19]==1)?`ALU_OP_SUB_REVERSE:`ALU_OP_ADD; ALU_OP<=(INSTRUCTION[19:19]==1)?`ALU_OP_SUB_REVERSE:`ALU_OP_ADD;
if ( IN_MOD == 3'b011 ) if ( IN_MOD == 3'b011 )
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
else else
next_state=`EXEC_MEMIO_READ; next_state=`EXEC_MEMIO_READ;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
11'b1111_0100_??? : begin 11'b1111_0100_??? : begin
/* HLT - Halt */ /* HLT - Halt */
/* 1 1 1 1 0 1 0 0 | */ /* 1 1 1 1 0 1 0 0 | */
opcode_size=0;
IN_MOD=3'b011; IN_MOD=3'b011;
HALT<=1; HALT<=1;
ERROR<=`ERR_NO_ERROR; ERROR<=`ERR_NO_ERROR;
MEM_OR_IO=0; MEM_OR_IO<=0;
seq_addr_entry<=`UCODE_NO_INSTRUCTION; seq_addr_entry<=`UCODE_NO_INSTRUCTION;
next_state=`EXEC_WAIT;
opcode_size=0;
Wbit=1;
in_alu_sel1=2'b10;
in_alu_sel2=2'b00;
PARAM2=16'hFFFF;
ALU_OP<=`ALU_OP_ADD_SIGNED_B;
OUT_MOD=3'b101;
MEM_OR_IO<=0;
next_state=`EXEC_WRITE_ENTRY;
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -537,18 +523,17 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
IN_MOD=3'b011; IN_MOD=3'b011;
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,3'b000}; reg_read_port2_addr<={Wbit,3'b000};
OUT_MOD=3'b100; OUT_MOD=3'b100;
ALU_OP=`ALU_OP_SUB_REVERSE; ALU_OP<=`ALU_OP_SUB_REVERSE;
MEM_OR_IO=0; MEM_OR_IO<=0;
if(Wbit==1) if(Wbit==1)
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
else begin else begin
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
//PARAM1[7:0]=INSTRUCTION[7:0]; TODO:needed?
end end
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -566,8 +551,8 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b10; in_alu_sel1=2'b10;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]}; PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
ALU_OP=`ALU_OP_ADD_SIGNED_B; ALU_OP<=`ALU_OP_ADD_SIGNED_B;
MEM_OR_IO=0; MEM_OR_IO<=0;
OUT_MOD=3'b101; OUT_MOD=3'b101;
case(INSTRUCTION[27:25]) case(INSTRUCTION[27:25])
3'b000: begin 3'b000: begin
@ -577,7 +562,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
else begin else begin
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end end
`normal_instruction; `normal_instruction
end end
3'b010: begin 3'b010: begin
/* Jump on (not) Zero */ /* Jump on (not) Zero */
@ -585,7 +570,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_NEXT_INSTRUCTION; next_state=`EXEC_NEXT_INSTRUCTION;
else else
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
end end
3'b100: begin 3'b100: begin
/* Jump on (not) Sign */ /* Jump on (not) Sign */
@ -593,7 +578,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_NEXT_INSTRUCTION; next_state=`EXEC_NEXT_INSTRUCTION;
else else
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
end end
3'b101: begin 3'b101: begin
/* Jump on (not) Parity */ /* Jump on (not) Parity */
@ -601,7 +586,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_NEXT_INSTRUCTION; next_state=`EXEC_NEXT_INSTRUCTION;
else else
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
end end
3'b001: begin 3'b001: begin
/* Jump on (not) Carry */ /* Jump on (not) Carry */
@ -609,10 +594,10 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
next_state=`EXEC_NEXT_INSTRUCTION; next_state=`EXEC_NEXT_INSTRUCTION;
else else
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
end end
default:begin default:begin
`invalid_instruction; /*We don't support that condition*/ `invalid_instruction /*We don't support that condition*/
end end
endcase endcase
DEPENDS_ON_PREVIOUS<=1; DEPENDS_ON_PREVIOUS<=1;
@ -626,11 +611,11 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
in_alu_sel1=2'b10; in_alu_sel1=2'b10;
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]}; PARAM2={{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
ALU_OP=`ALU_OP_ADD_SIGNED_B; ALU_OP<=`ALU_OP_ADD_SIGNED_B;
OUT_MOD=3'b101; OUT_MOD=3'b101;
MEM_OR_IO=0; MEM_OR_IO<=0;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -656,7 +641,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=0; opcode_size=0;
Wbit=1; Wbit=1;
Sbit=0; Sbit=0;
PARAM1=2; PARAM1<=2;
seq_addr_entry<=`UCODE_RET_ENTRY; seq_addr_entry<=`UCODE_RET_ENTRY;
`normal_microcoded `normal_microcoded
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
@ -682,7 +667,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=1; Wbit=1;
Sbit=0; Sbit=0;
PARAM2=2; PARAM2=2;
reg_read_port2_addr={1'b1,INSTRUCTION[26:24]}; reg_read_port2_addr<={1'b1,INSTRUCTION[26:24]};
seq_addr_entry<=`UCODE_PUSH_ENTRY; seq_addr_entry<=`UCODE_PUSH_ENTRY;
`normal_microcoded `normal_microcoded
memio_address_select=0; memio_address_select=0;
@ -695,18 +680,18 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=INSTRUCTION[24:24]; Wbit=INSTRUCTION[24:24];
IN_MOD={1'b0,INSTRUCTION[23:22]}; IN_MOD={1'b0,INSTRUCTION[23:22]};
RM={INSTRUCTION[18:16]}; RM={INSTRUCTION[18:16]};
MEM_OR_IO=0; MEM_OR_IO<=0;
if(Wbit==1)begin if(Wbit==1)begin
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
end else begin end else begin
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
end end
in_alu_sel1=2'b00; /* PARAM1 */ in_alu_sel1=2'b00; /* PARAM1 */
ALU_OP=`ALU_OP_AND; ALU_OP<=`ALU_OP_AND;
case(IN_MOD) case(IN_MOD)
3'b011:begin 3'b011:begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end end
default:begin default:begin
@ -715,7 +700,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
end end
endcase endcase
OUT_MOD=3'b100;/*NULL*/ OUT_MOD=3'b100;/*NULL*/
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -726,7 +711,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=INSTRUCTION[24:24]; Wbit=INSTRUCTION[24:24];
IN_MOD=3'b011; IN_MOD=3'b011;
RM=3'b000; RM=3'b000;
MEM_OR_IO=0; MEM_OR_IO<=0;
if(Wbit==1)begin if(Wbit==1)begin
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
end else begin end else begin
@ -734,11 +719,11 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
end end
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
in_alu_sel1=2'b00; /* PARAM1 */ in_alu_sel1=2'b00; /* PARAM1 */
ALU_OP=`ALU_OP_AND; ALU_OP<=`ALU_OP_AND;
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
OUT_MOD=3'b100;/*NULL*/ OUT_MOD=3'b100;/*NULL*/
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -748,8 +733,8 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=0; opcode_size=0;
Wbit=1; Wbit=1;
Sbit=0; Sbit=0;
PARAM1=2; PARAM1<=2;
reg_write_addr={1'b1,INSTRUCTION[26:24]}; reg_write_addr<={1'b1,INSTRUCTION[26:24]};
seq_addr_entry<=`UCODE_POP_ENTRY; seq_addr_entry<=`UCODE_POP_ENTRY;
`normal_microcoded `normal_microcoded
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
@ -762,19 +747,19 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=1; Wbit=1;
IN_MOD={1'b0,INSTRUCTION[23:22]}; IN_MOD={1'b0,INSTRUCTION[23:22]};
RM=INSTRUCTION[18:16]; RM=INSTRUCTION[18:16];
MEM_OR_IO=0; MEM_OR_IO<=0;
in_alu_sel1=2'b11; in_alu_sel1=2'b11;
if (IN_MOD==3'b011)begin if (IN_MOD==3'b011)begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end else begin end else begin
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
next_state=`EXEC_MEMIO_READ; next_state=`EXEC_MEMIO_READ;
end end
ALU_OP=`ALU_OP_ADD; ALU_OP<=`ALU_OP_ADD;
OUT_MOD=3'b101; OUT_MOD=3'b101;
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
end end
@ -785,7 +770,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=1; opcode_size=1;
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
in_alu_sel2=2'b11; in_alu_sel2=2'b11;
MEM_OR_IO=0; MEM_OR_IO<=0;
if(Wbit==1)begin if(Wbit==1)begin
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
end else begin end else begin
@ -795,7 +780,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
OUT_MOD={1'b0,INSTRUCTION[23:22]}; OUT_MOD={1'b0,INSTRUCTION[23:22]};
IN_MOD=3'b011; IN_MOD=3'b011;
RM=INSTRUCTION[18:16]; RM=INSTRUCTION[18:16];
`normal_instruction; `normal_instruction
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
@ -826,15 +811,17 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=0; opcode_size=0;
in_alu_sel1=2'b00; in_alu_sel1=2'b00;
in_alu_sel2=2'b11; in_alu_sel2=2'b11;
reg_read_port1_addr={Wbit,3'b000}; reg_read_port1_addr<={Wbit,3'b000};
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
MEM_OR_IO=1;
HALT <= 0; HALT <= 0;
PARAM1=0; PARAM1<=0;
OUT_MOD={3'b000}; OUT_MOD={3'b000};
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
IN_MOD=3'b011; IN_MOD=3'b011;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
`normal_instruction
MEM_OR_IO<=1;
ALU_OP<=`ALU_OP_ADD;
end end
11'b1100_1111_???:begin 11'b1100_1111_???:begin
/* IRET - Return from interrupt */ /* IRET - Return from interrupt */
@ -844,7 +831,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
opcode_size=0; opcode_size=0;
Wbit=1; Wbit=1;
Sbit=0; Sbit=0;
PARAM1=2; PARAM1<=2;
seq_addr_entry<=`UCODE_RET_ENTRY; seq_addr_entry<=`UCODE_RET_ENTRY;
`normal_microcoded `normal_microcoded
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
@ -859,7 +846,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
Wbit=INSTRUCTION[24:24]; Wbit=INSTRUCTION[24:24];
IN_MOD={1'b0,INSTRUCTION[23:22]}; IN_MOD={1'b0,INSTRUCTION[23:22]};
RM={INSTRUCTION[18:16]}; RM={INSTRUCTION[18:16]};
MEM_OR_IO=0; MEM_OR_IO<=0;
if(Wbit==1)begin if(Wbit==1)begin
PARAM_ACTION=`LOAD_16; PARAM_ACTION=`LOAD_16;
end else begin end else begin
@ -867,15 +854,15 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
end end
in_alu_sel1=2'b00; /* PARAM1 */ in_alu_sel1=2'b00; /* PARAM1 */
case(INSTRUCTION[21:19]) case(INSTRUCTION[21:19])
3'b100: ALU_OP=`ALU_OP_AND; 3'b100: ALU_OP<=`ALU_OP_AND;
3'b001: ALU_OP=`ALU_OP_OR; 3'b001: ALU_OP<=`ALU_OP_OR;
default:begin end default:begin end
endcase endcase
case(IN_MOD) case(IN_MOD)
3'b011:begin 3'b011:begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
reg_write_addr={Wbit,RM}; reg_write_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end end
default:begin default:begin
@ -886,7 +873,7 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
OUT_MOD=IN_MOD; OUT_MOD=IN_MOD;
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
memio_address_select=0; memio_address_select=0;
`normal_instruction; `normal_instruction
end end
11'b0000_00??_???,11'b0010_10??_???,11'b0011_10??_???:begin 11'b0000_00??_???,11'b0010_10??_???,11'b0011_10??_???:begin
/* CMP - Compare Register/memory and register */ /* CMP - Compare Register/memory and register */
@ -901,11 +888,11 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
IN_MOD=3'b011; IN_MOD=3'b011;
RM=INSTRUCTION[18:16]; RM=INSTRUCTION[18:16];
in_alu_sel1=2'b01;//constantly register in_alu_sel1=2'b01;//constantly register
reg_read_port1_addr={Wbit,INSTRUCTION[21:19]}; reg_read_port1_addr<={Wbit,INSTRUCTION[21:19]};
if(IN_MOD==3'b011)begin if(IN_MOD==3'b011)begin
in_alu_sel2=2'b01; in_alu_sel2=2'b01;
reg_read_port2_addr={Wbit,RM}; reg_read_port2_addr<={Wbit,RM};
reg_write_addr={Wbit,RM}; reg_write_addr<={Wbit,RM};
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
end else begin end else begin
in_alu_sel2=2'b00; in_alu_sel2=2'b00;
@ -915,12 +902,12 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
PARAM_ACTION=`LOAD_8; PARAM_ACTION=`LOAD_8;
end end
end end
MEM_OR_IO=0; MEM_OR_IO<=0;
memio_address_select=0; memio_address_select=0;
case (INSTRUCTION[29:26]) case (INSTRUCTION[29:26])
4'b0000: ALU_OP=`ALU_OP_ADD; 4'b0000: ALU_OP<=`ALU_OP_ADD;
4'b1010: ALU_OP=`ALU_OP_SUB; 4'b1010: ALU_OP<=`ALU_OP_SUB;
4'b1110: ALU_OP=`ALU_OP_SUB_REVERSE; 4'b1110: ALU_OP<=`ALU_OP_SUB_REVERSE;
default: begin end default: begin end
endcase endcase
case (INSTRUCTION[29:26]) case (INSTRUCTION[29:26])
@ -932,11 +919,33 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
DEPENDS_ON_PREVIOUS<=0; DEPENDS_ON_PREVIOUS<=0;
next_state=`EXEC_WRITE_ENTRY; next_state=`EXEC_WRITE_ENTRY;
if(INSTRUCTION[25:25]==1'b0) begin if(INSTRUCTION[25:25]==1'b0) begin
`normal_instruction; `normal_instruction
end else begin end else begin
`unimpl_addressing_mode; `unimpl_addressing_mode
end end
end end
11'b1110_010?_???:begin
/* IN - Read from a defined port to AL or AX */
/* | 1 1 1 0 0 1 0 W | DATA 8 | */
memio_address_select=1;
OUT_MOD=3'b011;
Wbit=INSTRUCTION[24:24];
opcode_size=0;
in_alu_sel1=2'b00;
in_alu_sel2=2'b00;
PARAM2= {8'b0,INSTRUCTION[23:16]}; //TODO: this is a bit of a hack, i should've used PARAM_ACTION but it loads into PARAM1 and messes up my next_state
PARAM1<=0;
reg_write_addr<={Wbit,3'b000};
reg_read_port1_addr<={Wbit,3'b000};
DEPENDS_ON_PREVIOUS<=0;
IN_MOD=3'b110;
MEM_OR_IO<=1;
HALT<=0;
ERROR<=0;
ALU_OP<=`ALU_OP_ADD;
next_state=`EXEC_MEMIO_READ_SETADDR;
seq_addr_entry<=`UCODE_NO_INSTRUCTION;
end
default:begin default:begin
`invalid_instruction `invalid_instruction
end end
@ -955,51 +964,52 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
default: begin end /*impossible*/ default: begin end /*impossible*/
endcase endcase
if(ucode_data[36:36]==0) /*Set reg write address*/ if(ucode_data[36:36]==0) /*Set reg write address*/
reg_write_addr = ucode_data[12:9 ]; reg_write_addr <= ucode_data[12:9 ];
in_alu_sel1 = ucode_data[14:13]; in_alu_sel1 = ucode_data[14:13];
in_alu_sel2 = ucode_data[16:15]; in_alu_sel2 = ucode_data[16:15];
OUT_MOD = ucode_data[19:17]; OUT_MOD = ucode_data[19:17];
/*1:1 map essentially but I want to keep the spec for these bits separate /*1:1 map essentially but I want to keep the spec for these bits separate
* from the alu op select bits*/ * from the alu op select bits*/
case(ucode_data[22:20]) case(ucode_data[22:20])
3'b000: ALU_OP=`ALU_OP_ADD; 3'b000: ALU_OP<=`ALU_OP_ADD;
3'b001: ALU_OP=`ALU_OP_SUB; 3'b001: ALU_OP<=`ALU_OP_SUB;
3'b010: ALU_OP=`ALU_OP_AND; 3'b010: ALU_OP<=`ALU_OP_AND;
3'b011: ALU_OP=`ALU_OP_OR; 3'b011: ALU_OP<=`ALU_OP_OR;
3'b100: ALU_OP=`ALU_OP_XOR; 3'b100: ALU_OP<=`ALU_OP_XOR;
3'b101: ALU_OP=`ALU_OP_ADD_SIGNED_B; 3'b101: ALU_OP<=`ALU_OP_ADD_SIGNED_B;
3'b110: ALU_OP=`ALU_OP_SUB_REVERSE; 3'b110: ALU_OP<=`ALU_OP_SUB_REVERSE;
3'b111: ALU_OP=`ALU_OP_SHIFT_LEFT; 3'b111: ALU_OP<=`ALU_OP_SHIFT_LEFT;
default: begin end default: begin end
endcase endcase
if(ucode_data[34:34]==0) /* Set reg read port 1 address */ if(ucode_data[34:34]==0) /* Set reg read port 1 address */
reg_read_port1_addr=ucode_data[26:23]; reg_read_port1_addr<=ucode_data[26:23];
IN_MOD=ucode_data[29:27]; IN_MOD=ucode_data[29:27];
if(ucode_data[35:35]==0) /* Set reg read port 1 address */ if(ucode_data[35:35]==0) /* Set reg read port 1 address */
reg_read_port2_addr=ucode_data[33:30]; reg_read_port2_addr<=ucode_data[33:30];
if(ucode_data[37:37]==1) /* Overwrite Wbit */ if(ucode_data[37:37]==1) /* Overwrite Wbit */
Wbit=ucode_data[38:38]; Wbit=ucode_data[38:38];
memio_address_select=ucode_data[39:39]; memio_address_select=ucode_data[39:39];
MEM_OR_IO=0; MEM_OR_IO<=0;
HALT <= 0; HALT <= 0;
ERROR <= 0; //TODO probably, right?
end end
if(PARAM_ACTION==`LOAD_8)begin if(PARAM_ACTION==`LOAD_8)begin
if(opcode_size==0)begin if(opcode_size==0)begin
if({Sbit,Wbit}==2'b11)begin if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/ /*signed "16bit" read*/
PARAM1 = {{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]}; PARAM1 <= {{8{INSTRUCTION[23:23]}},INSTRUCTION[23:16]};
end else begin end else begin
//PARAM1[7:0] = INSTRUCTION[23:16]; //PARAM1[7:0] = INSTRUCTION[23:16];
PARAM1 = {8'b0,INSTRUCTION[23:16]}; PARAM1 <= {8'b0,INSTRUCTION[23:16]};
end end
end else begin end else begin
if({Sbit,Wbit}==2'b11)begin if({Sbit,Wbit}==2'b11)begin
/*signed "16bit" read*/ /*signed "16bit" read*/
PARAM1 = {{8{INSTRUCTION[15:15]}},INSTRUCTION[15:8]}; PARAM1 <= {{8{INSTRUCTION[15:15]}},INSTRUCTION[15:8]};
end else begin end else begin
//PARAM1[7:0] = INSTRUCTION[15:8]; //PARAM1[7:0] = INSTRUCTION[15:8];
PARAM1 = {8'b0,INSTRUCTION[15:8]}; PARAM1 <= {8'b0,INSTRUCTION[15:8]};
end end
end end
case(IN_MOD) case(IN_MOD)
@ -1008,11 +1018,11 @@ always @( FLAGS or INSTRUCTION or SIMPLE_MICRO or seq_addr_input ) begin
endcase endcase
end else if (PARAM_ACTION == `LOAD_16) begin end else if (PARAM_ACTION == `LOAD_16) begin
if(opcode_size==0)begin if(opcode_size==0)begin
PARAM1[7:0] = INSTRUCTION[23:16]; PARAM1[7:0] <= INSTRUCTION[23:16];
PARAM1[15:8] = INSTRUCTION[15:8]; PARAM1[15:8] <= INSTRUCTION[15:8];
end else begin end else begin
PARAM1[15:8] = INSTRUCTION[7:0]; PARAM1[15:8] <= INSTRUCTION[7:0];
PARAM1[7:0] = INSTRUCTION[15:8]; PARAM1[7:0] <= INSTRUCTION[15:8];
end end
case(IN_MOD) case(IN_MOD)
3'b000,3'b001,3'b010: next_state = `EXEC_MEMIO_READ; 3'b000,3'b001,3'b010: next_state = `EXEC_MEMIO_READ;
@ -1029,7 +1039,7 @@ endmodule
/* IN: {INSTRUCTION[31:24],INSTRUCTION[21:19]} */ /* IN: {INSTRUCTION[31:24],INSTRUCTION[21:19]} */
/* OUT: number in bytes */ /* OUT: number in bytes */
module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT ); module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT );
always @( IN ) begin always @* begin
casez(IN) casez(IN)
11'b0000_010?_??? : VERDICT = 3'd2+{2'b0,IN[3:3]}; /* ADD - Add Immediate word/byte to accumulator */ 11'b0000_010?_??? : VERDICT = 3'd2+{2'b0,IN[3:3]}; /* ADD - Add Immediate word/byte to accumulator */
11'b1000_00??_101 : VERDICT = 3'd3+{2'b0,(IN[4:3]==2'b01)}; /* SUB - Subtract immediate word/byte from register/memory */ 11'b1000_00??_101 : VERDICT = 3'd3+{2'b0,(IN[4:3]==2'b01)}; /* SUB - Subtract immediate word/byte from register/memory */
@ -1060,14 +1070,15 @@ module InstrSize ( input [10:0] IN, output reg [2:0] VERDICT );
11'b0000_00??_??? : VERDICT = 3'd2; /* ADD - Reg/memory with register to either */ 11'b0000_00??_??? : VERDICT = 3'd2; /* ADD - Reg/memory with register to either */
11'b0010_10??_??? : VERDICT = 3'd2; /* SUB - Reg/memory with register to either */ 11'b0010_10??_??? : VERDICT = 3'd2; /* SUB - Reg/memory with register to either */
11'b0011_10??_??? : VERDICT = 3'd2; /* CMP - Compare Register/memory and register */ 11'b0011_10??_??? : VERDICT = 3'd2; /* CMP - Compare Register/memory and register */
11'b1110_010?_??? : VERDICT = 3'd2; /* IN - Read from a defined port to AL or AX */
default: VERDICT = 3'd7; default: VERDICT = 3'd7;
endcase endcase
end end
endmodule endmodule
`ifdef INCLUDE_EARLY_CALC_CIRUIT `ifdef INCLUDE_EARLY_CALC_CIRCUIT
module Is1 ( input [7:0] IN, output reg VERDICT ); module Is1 ( input [7:0] IN, output reg VERDICT );
always @( IN ) begin always @* begin
casez(IN) casez(IN)
8'b0100_???? : VERDICT = 1; /* DEC - Decrement Register | INC - Increment Register */ 8'b0100_???? : VERDICT = 1; /* DEC - Decrement Register | INC - Increment Register */
8'b1111_0100 : VERDICT = 1; /* HLT - Halt */ 8'b1111_0100 : VERDICT = 1; /* HLT - Halt */

View File

@ -3,7 +3,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -21,6 +21,7 @@
`define EXEC_STATE_BITS 4 `define EXEC_STATE_BITS 4
//TODO: Please clean this up
`define EXEC_WAIT 4'b1100 `define EXEC_WAIT 4'b1100
/*DECODE SATE*/ /*DECODE SATE*/

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -42,10 +42,10 @@ module execute_unit (
/* */ ,output reg biu_read_request, output reg biu_jump_req,output reg biu_write_request /* */ ,output reg biu_read_request, output reg biu_jump_req,output reg biu_write_request
/*************** INPUT FROM BIU ****************/ /*************** INPUT FROM BIU ****************/
/* */ ,input BIU_VALID_DATA, input biu_data_direction /* */ ,input BIU_VALID_DATA,input [15:0] BIU_EX_DATA_READ
/************ BIDIRECTIONAL WITH BIU ***********/ /**************** OUTPUT TO BIU ****************/
/* */ ,inout [15:0] BIU_DATA /* */ ,output [15:0] BIU_EX_DATA_WRITE
/***************** REGISTERS *****************/ /***************** REGISTERS *****************/
/* */ ,input [15:0] reg_read_port1_data ,input [15:0] reg_read_port2_data, output reg [3:0] reg_read_port1_addr /* */ ,input [15:0] reg_read_port1_data ,input [15:0] reg_read_port2_data, output reg [3:0] reg_read_port1_addr
@ -57,7 +57,7 @@ assign _ALU_O_ = ALU_O;
reg [`EXEC_STATE_BITS-1:0] exec_state; reg [`EXEC_STATE_BITS-1:0] exec_state;
reg [15:0] PARAM1,PARAM2; reg [15:0] PARAM1,PARAM2;
assign BIU_DATA = biu_data_direction ? (memio_address_select ? reg_read_port1_data : ALU_O): 16'hz; assign BIU_EX_DATA_WRITE = memio_address_select ? reg_read_port1_data : ALU_O;
/*############ ALU / Execution units ################################################## */ /*############ ALU / Execution units ################################################## */
@ -93,32 +93,19 @@ ALU ALU1(
/*############ Execute logic ########################################################## */ /*############ Execute logic ########################################################## */
always @(valid_input) begin
exec_state <= init_state;
reg_write_we <= 1;
biu_jump_req <= 0;
use_exec_reg_addr <= 0;
end
always @( set_initial_values) begin
PARAM1 <= PARAM1_INIT;
PARAM2 <= PARAM2_INIT;
end
always @(negedge reset) begin
exec_state <= `EXEC_WAIT;
end
always @(posedge reset) begin
exec_state <= `EXEC_RESET;
next_exec <= 0;
end
`define unimpl_addressing_mode exec_state <= `EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE; `define unimpl_addressing_mode exec_state <= `EXEC_WAIT;ERROR <= `ERR_UNIMPL_ADDRESSING_MODE;
`define finished_instruction next_exec<=!next_exec; exec_state <= `EXEC_WAIT; `define finished_instruction exec_state <= `EXEC_WAIT;next_exec<=1;
always @(posedge clock) begin 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) case (exec_state)
`EXEC_RESET: begin `EXEC_RESET: begin
biu_write_request <= 0; biu_write_request <= 0;
@ -126,10 +113,16 @@ always @(posedge clock) begin
biu_jump_req <= 0; biu_jump_req <= 0;
reg_write_we <= 1; reg_write_we <= 1;
exec_state <= `EXEC_WAIT; exec_state <= `EXEC_WAIT;
next_exec <= 0;
ERROR <= `ERR_NO_ERROR; ERROR <= `ERR_NO_ERROR;
end end
`EXEC_WAIT:begin `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; reg_write_we <= 1;
use_exec_reg_addr <= 0; use_exec_reg_addr <= 0;
ERROR<=`ERR_NO_ERROR; ERROR<=`ERR_NO_ERROR;
@ -203,6 +196,9 @@ always @(posedge clock) begin
endcase endcase
end end
`EXEC_MEMIO_READ_SETADDR:begin `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) if(memio_address_select==0)
BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0]; BIU_ADDRESS_INPUT <= reg_read_port1_data[15:0];
else else
@ -210,7 +206,7 @@ always @(posedge clock) begin
if ( BIU_VALID_DATA == 1 ) begin if ( BIU_VALID_DATA == 1 ) begin
exec_state <= `EXEC_WRITE_ENTRY; exec_state <= `EXEC_WRITE_ENTRY;
PARAM2 <= BIU_DATA; PARAM2 <= BIU_EX_DATA_READ;
biu_read_request <= 0; biu_read_request <= 0;
end else begin end else begin
biu_read_request <= 1; biu_read_request <= 1;
@ -311,7 +307,7 @@ always @(posedge clock) begin
else else
BIU_ADDRESS_INPUT <= ALU_O; BIU_ADDRESS_INPUT <= ALU_O;
if (write == 0) begin //TODO: don't do it that was or better yet don't do it at all somehow 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; biu_write_request <= 0;
`finished_instruction `finished_instruction
end end
@ -320,6 +316,8 @@ always @(posedge clock) begin
default:begin default:begin
end end
endcase endcase
end
end
end end
endmodule endmodule

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. 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 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 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. 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 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 it under the terms of the GNU General Public License as published by
@ -19,30 +19,55 @@
/* This warning is because we don't use the full address bus. */ /* This warning is because we don't use the full address bus. */
/* verilator lint_off UNUSEDSIGNAL */ /* 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 */ /* verilator lint_on UNUSEDSIGNAL */
reg [15:0] memory [0:32768]; reg [15:0] memory [0:(RAM_SIZE_IN_BYTES/2)-1];
initial begin initial begin
`ifndef YOSYS
string boot_code; string boot_code;
if(!$value$plusargs("BOOT_CODE=%s",boot_code))begin if(!$value$plusargs("BOOT_CODE=%s",boot_code))begin
$display("No boot code specified. Please add +BOOT_CODE=<path> to your vvp args"); $display("No boot code specified. Please add +BOOT_CODE=<path> to your vvp args");
$finish; $finish;
end 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 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( cs == 0 ) begin always @(posedge clock) begin
if( cs == 0 && wr == 0) begin
if(BHE==0) if(BHE==0)
memory[address[16:1]][7:0]<=data[15:8]; memory[address[ADDRESS_WIDTH-1:1]][7:0]<=cpu_write_data[15:8];
if(address[0]==0) if(address[0]==0)
memory[address[16:1]][15:8]<=data[7:0]; memory[address[ADDRESS_WIDTH-1:1]][15:8]<=cpu_write_data[7:0];
end end
end end

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

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -20,6 +20,7 @@
`include "exec_state_def.v" `include "exec_state_def.v"
`include "alu_header.v" `include "alu_header.v"
`include "config.v" `include "config.v"
`include "error_header.v"
//HALT: active high //HALT: active high
//IOMEM: 1=IO 0=MEM //IOMEM: 1=IO 0=MEM
@ -31,19 +32,19 @@
module processor ( module processor (
/* MISC */ input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR /* MISC */ input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR
/* MEMORY / IO */ ,output [19:0] external_address_bus, inout [15:0] external_data_bus,output read, output write,output BHE,output IOMEM /* 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
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
/* STATISTICS */ ,output wire new_instruction /* STATISTICS */ ,output wire new_instruction
`endif `endif
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
/* */ ,output wire [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT, output wire VALID_INSTRUCTION_STAT, output wire jump_req_debug /* */ ,output wire [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT, output wire VALID_INSTRUCTION_STAT, output wire jump_req_debug
`endif `endif
); );
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
assign jump_req_debug=biu_jump_req; assign jump_req_debug=biu_jump_req;
`endif `endif
@ -84,10 +85,10 @@ execute_unit execute_unit (
/* */ ,biu_read_request, biu_jump_req, biu_write_request /* */ ,biu_read_request, biu_jump_req, biu_write_request
/*************** INPUT FROM BIU ****************/ /*************** INPUT FROM BIU ****************/
/* */ ,BIU_VALID_DATA, BIU_DATA_DIR /* */ ,BIU_VALID_DATA,BIU_EX_DATA_READ
/************ BIDIRECTIONAL WITH BIU ***********/ /**************** OUTPUT TO BIU ****************/
/* */ ,BIU_DATA /* */ ,BIU_EX_DATA_WRITE
/***************** REGISTERS *****************/ /***************** REGISTERS *****************/
/* */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr /* */ ,reg_read_port1_data, reg_read_port2_data, EXEC_reg_read_port1_addr
@ -98,11 +99,10 @@ execute_unit execute_unit (
/*############ Bus Interface Unit ############################################### */ /*############ Bus Interface Unit ############################################### */
wire [15:0] INSTRUCTION_LOCATION; wire [15:0] INSTRUCTION_LOCATION;
wire [15:0] BIU_DATA; wire [15:0] BIU_EX_DATA_READ,BIU_EX_DATA_WRITE;
wire [31:0] IF2DE_INSTRUCTION; wire [31:0] IF2DE_INSTRUCTION;
wire BIU_VALID_DATA; wire BIU_VALID_DATA;
wire VALID_INSTRUCTION; wire VALID_INSTRUCTION;
wire BIU_DATA_DIR;
BIU BIU( BIU BIU(
/***************** GENERAL *****************/ /***************** GENERAL *****************/
@ -110,23 +110,24 @@ BIU BIU(
/**************** OUTSIDE WORLD ****************/ /**************** OUTSIDE WORLD ****************/
/* */ ,external_address_bus /* */ ,external_address_bus
/* */ ,external_data_bus,read,write,BHE,IOMEM /* */ ,external_data_bus_read,external_data_bus_write,read,write,BHE,IOMEM
/* */ ,wait_state
/**************** OUTPUT TO DE ****************/ /**************** OUTPUT TO DE ****************/
/* */ ,IF2DE_INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION /* */ ,IF2DE_INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION
/* */ ,BIU_VALID_DATA,BIU_DATA_DIR /* */ ,BIU_VALID_DATA
/**************** INPUT FROM DE ****************/ /**************** INPUT FROM DE ****************/
,Wbit,MEM_OR_IO,VALID_INSTRUCTION_ACK ,Wbit,MEM_OR_IO,VALID_INSTRUCTION_ACK
/**************** INPUT FROM EX ****************/ /**************** INPUT FROM EX ****************/
/* */ ,biu_jump_req,biu_write_request,biu_read_request /* */ ,biu_jump_req,biu_write_request,biu_read_request
/* */ ,BIU_ADDRESS_INPUT /* */ ,BIU_ADDRESS_INPUT,BIU_EX_DATA_WRITE
/************ BIDIRECTIONAL WITH EX ************/ /***************** OUTPUT TO EX ****************/
/* */ ,BIU_DATA /* */ ,BIU_EX_DATA_READ
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
/***************** STATISTICS *****************/ /***************** STATISTICS *****************/
/* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT /* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT
`endif `endif
@ -188,13 +189,14 @@ assign reg_read_port1_addr = use_exec_reg_addr ? EXEC_reg_read_port1_addr : DE_r
wire [15:0] reg_read_port1_data, reg_read_port2_data; wire [15:0] reg_read_port1_data, reg_read_port2_data;
register_file register_file( register_file register_file(
/* WRITE */ .write_port1_addr(reg_write_addr), /* WRITE */ .write_port1_addr(reg_write_addr), //TODO: should this come from exec instead?
/* */ .write_port1_data(ALU_O), /* */ .write_port1_data(ALU_O),
/* */ .write_port1_we(reg_write_we), /* */ .write_port1_we(reg_write_we),
/* READ 1 */ .read_port1_addr(reg_read_port1_addr), /* READ 1 */ .read_port1_addr(reg_read_port1_addr),
/* */ .read_port1_data(reg_read_port1_data), /* */ .read_port1_data(reg_read_port1_data),
/* READ 2 */ .read_port2_addr(DE_reg_read_port2_addr), /* READ 2 */ .read_port2_addr(DE_reg_read_port2_addr),
/* */ .read_port2_data(reg_read_port2_data) /* */ .read_port2_data(reg_read_port2_data),
/* GENERAL */ .clock(clock)
); );
/*############################################################################### */ /*############################################################################### */

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -21,7 +21,8 @@
/* Register address format: /* Register address format:
* [W-bit] [ 3-bit address] */ * [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] write_port1_addr;
input [3:0] read_port1_addr; input [3:0] read_port1_addr;
input [3:0] read_port2_addr; input [3:0] read_port2_addr;
@ -32,11 +33,11 @@ input write_port1_we;
reg [15:0] registers [7:0]; 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] : 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] ) ); ( 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] : 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] ) ); ( 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] ) );
@ -48,7 +49,8 @@ assign read_port2_data[7:0] = ( read_port2_addr[3:3] ? registers[read_port2_addr
wire write_Wbit; wire write_Wbit;
assign write_Wbit=write_port1_addr[3:3]; assign write_Wbit=write_port1_addr[3:3];
always @(negedge write_port1_we) begin always @(posedge clock) begin
if(write_port1_we==0)begin
if(write_Wbit==1)begin if(write_Wbit==1)begin
/* Word : AX,CX,DX,BX,SP,BP,SI,DI */ /* Word : AX,CX,DX,BX,SP,BP,SI,DI */
registers[write_port1_addr[2:0]] <= write_port1_data; registers[write_port1_addr[2:0]] <= write_port1_data;
@ -88,7 +90,7 @@ always @(negedge write_port1_we) begin
debug_address<={1'b0,write_port1_addr[1:0]}; debug_address<={1'b0,write_port1_addr[1:0]};
`endif `endif
end
end end
`ifdef DEBUG_REG_WRITES `ifdef DEBUG_REG_WRITES

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -22,41 +22,54 @@
`include "config.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_BITS-1:0] 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);
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
wire new_instruction; wire new_instruction;
`endif `endif
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
wire unsigned [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT; wire unsigned [`L1_CACHE_SIZE-1:0] L1_SIZE_STAT;
wire VALID_INSTRUCTION_STAT,jump_req; wire VALID_INSTRUCTION_STAT,jump_req;
`endif `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( processor p(
/* MISC */ clock,reset,HALT,ERROR /* MISC */ clock,reset,HALT,ERROR
/* MEMORY / IO */ ,address_bus,data_bus,rd,wr,BHE,IOMEM /* MEMORY / IO */ ,address_bus,data_bus_read_CPU,data_bus_write_CPU,wait_state,rd,wr,BHE,IOMEM
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
/* STATISTICS */ ,new_instruction /* STATISTICS */ ,new_instruction
`endif `endif
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
/* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT, jump_req /* */ ,L1_SIZE_STAT, VALID_INSTRUCTION_STAT, jump_req
`endif `endif
); );
doublemem sysmem(address_bus,data_bus,rd,wr,BHE,IOMEM); wire [15:0] data_bus_read_RAM;
`ifdef OTUPUT_JSON_STATISTICS 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; string stats_name,version,commit;
integer json_file_descriptor; integer json_file_descriptor;
`endif `endif
`ifndef YOSYS
string waveform_name; string waveform_name;
`endif
initial begin initial begin
`ifndef SYNTHESIS
if($value$plusargs("WAVEFORM=%s",waveform_name))begin if($value$plusargs("WAVEFORM=%s",waveform_name))begin
$dumpfile(waveform_name); $dumpfile(waveform_name);
$dumpvars(0,p,cycles); $dumpvars(0,p,cycles);
end end
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
if(!$value$plusargs("VERSION=%s",version)) version="unkown"; if(!$value$plusargs("VERSION=%s",version)) version="unkown";
if(!$value$plusargs("COMMIT=%s",commit)) commit="unkown"; if(!$value$plusargs("COMMIT=%s",commit)) commit="unkown";
if($value$plusargs("STATS=%s",stats_name))begin if($value$plusargs("STATS=%s",stats_name))begin
@ -68,6 +81,7 @@ initial begin
`endif `endif
sane=0; sane=0;
finish=0; finish=0;
`endif
end end
//integer killswitch=0; //integer killswitch=0;
@ -81,7 +95,7 @@ end
// end // end
//end //end
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
reg first_json_cycle; reg first_json_cycle;
always @(negedge clock)begin always @(negedge clock)begin
if(finish < 2 && json_file_descriptor!=0 && sane)begin if(finish < 2 && json_file_descriptor!=0 && sane)begin
@ -91,32 +105,66 @@ always @(negedge clock)begin
end end
`endif `endif
reg [15:0]data_bus_IO;
`ifndef SYNTHESIS
always @(negedge wr) begin always @(negedge wr) begin
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 ) if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
$write("%s" ,data_bus[15:8]); $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
end end
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
end
`endif
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
/* verilator lint_off MULTIDRIVEN */
reg [128:0] instruction_count; reg [128:0] instruction_count;
/* verilator lint_on MULTIDRIVEN */
always @(new_instruction) begin always @(new_instruction) begin
instruction_count<=instruction_count+1; instruction_count<=instruction_count+1;
end end
`endif `endif
reg [1:0] finish;
string memdump_name; `ifndef SYNTHESIS
always @(posedge HALT) begin
`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 if($value$plusargs("MEMDUMP=%s",memdump_name))begin
$writememh(memdump_name, sysmem.memory,0,32767); $writememh(memdump_name, sysmem.memory,0,32767);
end end
finish<=2'd1; finish<=2'd1;
end end
`ifdef OTUPUT_JSON_STATISTICS /* verilator lint_off MULTIDRIVEN */
reg [128:0] instruction_count_temp; reg [1:0] finish;
`endif /* verilator lint_on MULTIDRIVEN */
always @(posedge clock) begin
reg sane;
reg [128:0] cycles;
always @(posedge reset)begin
sane<=1;
end
always @(posedge clock) begin
/* Allow some clock cycles for the waveform*/ /* Allow some clock cycles for the waveform*/
case(finish) case(finish)
2'd0: begin end 2'd0: begin end
@ -125,30 +173,26 @@ always @(posedge clock) begin
/* instruction_count gets updated at the sme time as HALT is pulled so wait a clock cycle to get an accurate reading*/ /* 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); $display("\x1b[7mProcessor halted.\nCycles run for : %0d\x1b[m",cycles);
`ifdef CALCULATE_IPC `ifdef CALCULATE_IPC
/* verilator lint_off REALCVT */
$display("\x1b[7mInstr. per cycle : %f\x1b[m", $itor(instruction_count) / $itor(cycles) ); $display("\x1b[7mInstr. per cycle : %f\x1b[m", $itor(instruction_count) / $itor(cycles) );
/* verilator lint_on REALCVT */
`endif `endif
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
instruction_count_temp <= instruction_count; instruction_count_temp <= instruction_count;
`endif `endif
end end
2'd2: begin 2'd2: begin
finish <= 3; finish <= 3;
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
if(json_file_descriptor!=0) if(json_file_descriptor!=0)
$fdisplay(json_file_descriptor,"],\n\"Total Cycles\":%0d,\n\"Instructions run\":%0d\n}",cycles-1,instruction_count_temp); $fdisplay(json_file_descriptor,"],\n\"Total Cycles\":%0d,\n\"Instructions run\":%0d\n}",cycles-1,instruction_count_temp);
`endif `endif
$finish;
end
2'd3: begin
end end
2'd3: $finish;
endcase endcase
end end
always @(posedge reset)begin always @( ERROR ) begin
sane<=1;
end
reg sane;
always @( ERROR ) begin
if ( ERROR != `ERR_NO_ERROR && sane == 1 ) begin if ( ERROR != `ERR_NO_ERROR && sane == 1 ) begin
$display("PROCESSOR RUN INTO AN ERROR."); $display("PROCESSOR RUN INTO AN ERROR.");
case (ERROR) case (ERROR)
@ -167,20 +211,21 @@ always @( ERROR ) begin
end end
finish<=2'd1; finish<=2'd1;
end end
end end
reg [128:0] cycles; always @(negedge clock)begin
always @(negedge clock)begin
if(reset==1) if(reset==1)
cycles<=cycles+1; cycles<=cycles+1;
else begin else begin
cycles<=0; cycles<=0;
`ifdef OTUPUT_JSON_STATISTICS `ifdef OUTPUT_JSON_STATISTICS
instruction_count <= 0; instruction_count <= 0;
`endif `endif
end end
end end
`endif
endmodule endmodule

View File

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

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 it under the terms of the GNU General Public License as published by
@ -25,7 +25,7 @@ wire clock;
reg reset; reg reset;
reg clk_enable; reg clk_enable;
wire [19:0]address_bus; wire [19:0]address_bus;
wire [15:0]data_bus; wire [15:0]data_bus_write;
wire rd,wr,HALT; wire rd,wr,HALT;
wire [2:0] ERROR; wire [2:0] ERROR;
wire IOMEM; wire IOMEM;
@ -33,7 +33,7 @@ wire IOMEM;
system system( .clock(clock), system system( .clock(clock),
.reset(reset), .reset(reset),
.address_bus(address_bus), .address_bus(address_bus),
.data_bus(data_bus), .data_bus_write(data_bus_write),
.rd(rd), .rd(rd),
.wr(wr), .wr(wr),
.HALT(HALT), .HALT(HALT),
@ -49,22 +49,26 @@ initial begin
do_reset = 0; do_reset = 0;
end end
reg [1:0]do_reset; reg [2:0]do_reset;
always @(posedge clock) begin always @(posedge clock) begin
case(do_reset) case(do_reset)
2'd0:begin 3'd0:begin
do_reset<=1; do_reset<=1;
end end
2'd1:begin 3'd1:begin
do_reset<=2; do_reset<=2;
reset <= 0; reset <= 0;
end end
2'd2:begin 3'd2:begin
do_reset<=3; do_reset<=3;
reset <= 0;
end
3'd3:begin
do_reset<=4;
reset <= 1; reset <= 1;
end end
2'd3:begin 3'd4:begin
end end
endcase endcase
end end

View File

@ -2,7 +2,7 @@
This file is part of the 9086 project. 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 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 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. 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 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 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

View File

@ -1,11 +1,29 @@
#!/bin/sh #!/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 set -euf
print_help(){ print_help(){
echo "$0 <json data file> <function> <output filename>" echo "$0 <json data file> <function> <output filename>"
echo " Possible functions:" echo " Possible functions:"
echo " cache_time : graph of cache utilisation in bytes over time in clock cycles" echo " cache_time : graph of cache utilisation in bytes over time in clock cycles"
echo " cache_util_freq : graph of the likelyhood of the cache for each utilisation" echo " cache_util_freq : graph of the likelihood of the cache for each utilisation"
} }
if [ "$#" != 3 ] || ! [ -e "$1" ] if [ "$#" != 3 ] || ! [ -e "$1" ]