From 63ea29e3992af286d9f0616a5c05bc50d6cba58d Mon Sep 17 00:00:00 2001 From: "(Tim) Efthimis Kritikos" Date: Sun, 3 Dec 2023 19:24:12 +0000 Subject: [PATCH] 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) --- .gitignore | 2 + Makefile | 6 +- README.md | 6 + boot_code/Makefile | 4 +- boot_code/bios.asm | 395 ++++++++++++++++++ boot_code/brainfuck_compiled.asm | 17 +- boot_code/brainfuck_compiler_v1.asm | 20 +- boot_code/brainfuck_interpreted.asm | 8 +- boot_code/brainfuck_mandelbrot.asm | 18 +- boot_code/colored_led.asm | 28 +- boot_code/dos_layer.asm | 16 +- boot_code/fibonacci.asm | 7 +- boot_code/gnome_sort.asm | 9 +- boot_code/pipeline_ideal.asm | 4 +- common.mk | 12 +- system/Makefile | 22 +- system/biu.v | 13 +- system/boot_code.asm | 18 +- system/config.v | 9 - .../fpga_config/OrangeCrab_r0.2.1/fpga_top.v | 243 ++++++++++- system/memory.v | 43 +- system/peripherals/Wishbone_IO_driver.v | 127 ++++++ system/peripherals/Wishbone_memory_driver.v | 149 +++++++ system/processor.v | 3 +- system/system.v | 5 +- tools/gen_litedram.sh | 92 ++++ 26 files changed, 1158 insertions(+), 118 deletions(-) create mode 100644 boot_code/bios.asm create mode 100644 system/peripherals/Wishbone_IO_driver.v create mode 100644 system/peripherals/Wishbone_memory_driver.v create mode 100755 tools/gen_litedram.sh diff --git a/.gitignore b/.gitignore index 9bd1180..58ab0dd 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,10 @@ abc.history system/synth_ecp5_out.config boot_code/*.bin boot_code/*.txt +boot_code/*.stxt system/boot_code.bin system/boot_code.txt system/obj_dir/ system/simplified_ucode.txt tools/*svg +system/external_ip/litedram_core_ecp5_phy.v diff --git a/Makefile b/Makefile index f49664b..4426486 100644 --- a/Makefile +++ b/Makefile @@ -21,7 +21,7 @@ VERILATOR_BIN=system/obj_dir/Vsystem BOOT_CODE=boot_code/brainfuck_mandelbrot.txt GTKWSAVE=./gtkwave_savefile.gtkw MICROCODE=system/ucode.txt -BOOTABLES=boot_code/brainfuck_compiled.txt boot_code/brainfuck_interpreted.txt boot_code/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 +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 NO_ASM=1 include common.mk @@ -29,7 +29,7 @@ include common.mk .PHONY: ${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/,,$@) boot_code/%.txt: @@ -48,5 +48,5 @@ clean: ${Q}make ${MAKEOPTS} -C system clean ${Q}make ${MAKEOPTS} -C boot_code clean -upload: boot_code/brainfuck_compiled.txt +upload: boot_code/bios.stxt make -C system upload diff --git a/README.md b/README.md index 310bcda..688bbf6 100644 --- a/README.md +++ b/README.md @@ -48,6 +48,12 @@ Additionally, for ECP5 FPGAs: * prjtrellis : 1.4 ( database commit 4dda149b9e4f1753ebc8b011ece2fe794be1281a ) * nextpnr : 0.6 +Additionally, if you need a DRAM/DDR controller, the project supports litedram: + +* Litedram : 2023.08 +* Migen : 0.9.2 +* Litex : 2023.08 + Additionally, for FPGAs using the [foboot](https://github.com/im-tomu/foboot) bootloader * dfu-util : 0.11 diff --git a/boot_code/Makefile b/boot_code/Makefile index 4fa7926..a9d1bba 100644 --- a/boot_code/Makefile +++ b/boot_code/Makefile @@ -1,5 +1,5 @@ -SOURCE=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 -BINARIES=$(subst .asm,.txt,${SOURCE}) +SOURCE=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 bios.asm +BINARIES=$(subst .asm,.txt,${SOURCE}) $(subst .asm,.stxt,${SOURCE}) BUILD_FILES=${BINARIES} BUILD_FILES+=$(subst .asm,.memdump,${SOURCE}) BUILD_FILES+=$(subst .asm,.fst,${SOURCE}) diff --git a/boot_code/bios.asm b/boot_code/bios.asm new file mode 100644 index 0000000..01da10c --- /dev/null +++ b/boot_code/bios.asm @@ -0,0 +1,395 @@ +.org 0xF800 +mov sp,#STACK +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,#0x2000 +MOV AX,#0xAAAA +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV AX,#0x6666 +MOV AX,[DI] +CMP AX,#0xAAAA +JNZ FAILED +MOV BX,#MEMTEST_PASS +CALL print + +MOV AL,#0x48 +MOV [DI],AX +MOV AL,#0x00 +MOV AX,[DI] +out byte #0xA5 + +MOV DI,#0x3000 +MOV AL,#0x65 +MOV [DI],AX +MOV AL,#0x00 +MOV AX,[DI] +out byte #0xA5 + +MOV DI,#0x4000 +MOV AL,#0x6c +MOV [DI],AX +MOV AL,#0x00 +MOV AX,[DI] +out byte #0xA5 + +MOV DI,#0x5000 +MOV AL,#0x6c +MOV [DI],AX +MOV AL,#0x00 +MOV AX,[DI] +out byte #0xA5 + +MOV DI,#0x6000 +MOV AL,#0x6f +MOV [DI],AX +MOV AL,#0x00 +MOV AX,[DI] +out byte #0xA5 + +HLT +FAILED: +MOV BX,#MEMTEST_FAIL +CALL print + +MOV DL,#0xF0 +DELAY51: +MOV AX,#0x5000 +DELAY5: +INC AX +JNZ DELAY5 +INC DL +JNZ DELAY51 + +MOV DI,#0x2000 +MOV AX,#0xAAAA +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV [DI],AX +MOV AX,#0x0000 +MOV AX,[DI] +CMP AL,#0xAA +JNZ FAILED2 +MOV BX,#MEMTEST_PASS +CALL print +HLT +FAILED2: +MOV BX,#MEMTEST_FAIL +CALL print +MOV AX,[DI] +CMP AL,#0xAA +JNZ FAILED3 +MOV BX,#MEMTEST_PASS +CALL print +HLT +FAILED3: +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 + +print: +mov al,[bx] +cmp al,#0 +je print_exit +out byte #0xA5 +inc bx +jmp print +print_exit: +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' + .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 diff --git a/boot_code/brainfuck_compiled.asm b/boot_code/brainfuck_compiled.asm index 5a61d47..fdc37a4 100644 --- a/boot_code/brainfuck_compiled.asm +++ b/boot_code/brainfuck_compiled.asm @@ -1,15 +1,22 @@ ; Interrupt table and routines -INCLUDE dos_layer.asm org 0x100 -INCLUDE brainfuck_compiler_v1.asm +output_program: +org 0xF800 +mov sp,#SMALL_STACK +call INIT_INT_VECT_TABLE +INCLUDE brainfuck_compiler_v1.asm +SMALL_STACK: + +INCLUDE dos_layer.asm prog: INCLUDE hello_9086.bf.asm -output_program: - .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xF800 JMP AX + +.ORG 0xFFFF +DB 0x00 ;Make sure a full 64KiB image diff --git a/boot_code/brainfuck_compiler_v1.asm b/boot_code/brainfuck_compiler_v1.asm index 791e4cf..87e39df 100644 --- a/boot_code/brainfuck_compiler_v1.asm +++ b/boot_code/brainfuck_compiler_v1.asm @@ -17,6 +17,8 @@ ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . +; 0x0000-0x0100 int vector 0x0100-0x0700 data 0x0700-0xC000 program data + mov sp,#STACK mov bx,#bootup_msg mov ah,#0x02 @@ -39,7 +41,7 @@ jmp print2 exit: MOV SI,#prog -MOV DI,#output_program +MOV DI,#0x0700 ;CL: write concat CH: move concat MOV CX,#0 JMP COMPILE ; Moving some functions above the main switch to make shot jumps work @@ -148,8 +150,9 @@ jne print3 MOV AL,#0xF4 ; hlt MOV [DI],AL -MOV BX,#DATA -MOV AX,#output_program +; From 0x100 its free but i'll do 0x200 in case it start writing earlier +MOV BX,#0x0200 +MOV AX,#0x0700 JMP AX ;;;;;;;;; . ;;;;;;;;; @@ -250,18 +253,19 @@ MOV AL,#0x43 ; inc %bx STOSB JMP MOVES_FLUSHED + MOVES_ONE_LEFT: MOV AL,#0x4b ; dec %bx STOSB JMP MOVES_FLUSHED + MOVES_FLUSHED: MOV CH,#0 RET -bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n' -compiling: .ASCII 'Compiling...\0' compiled: .ASCII '\rCompiled! \n' -DATA: .BLKB 560 - .BLKB 200 -STACK: +compiling: .ASCII 'Compiling...\0' +bootup_msg: .ASCII 'Native 8086 brainfuck compiler v1\n' + .BLKB 6 ; Using the text as stack space for the compiled program +STACK: ; brainfuck_mandelbrot depends on stack being at the end diff --git a/boot_code/brainfuck_interpreted.asm b/boot_code/brainfuck_interpreted.asm index 221e59d..b96aef6 100644 --- a/boot_code/brainfuck_interpreted.asm +++ b/boot_code/brainfuck_interpreted.asm @@ -1,16 +1,16 @@ -; Interrupt table and routines -INCLUDE dos_layer.asm -ORG 0x100 +ORG 0xF000 mov sp,#STACK +call INIT_INT_VECT_TABLE INCLUDE brainfuck_interpreter_v0.asm .BLKB 200 STACK: +INCLUDE dos_layer.asm prog: INCLUDE hello_9086.bf.asm .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xF000 JMP AX diff --git a/boot_code/brainfuck_mandelbrot.asm b/boot_code/brainfuck_mandelbrot.asm index a3bd259..ecce2d3 100644 --- a/boot_code/brainfuck_mandelbrot.asm +++ b/boot_code/brainfuck_mandelbrot.asm @@ -1,14 +1,22 @@ -; Interrupt table and routines -INCLUDE dos_layer.asm +;I got this down to 11428 bytes -.ORG 0x100 +org 0x100 +output_program: + +org 0xD000 +mov sp,#SMALL_STACK +call INIT_INT_VECT_TABLE INCLUDE brainfuck_compiler_v1.asm +SMALL_STACK:;Stack of compiler is at the end of file +INCLUDE dos_layer.asm prog: INCLUDE mandelbrot.bf.asm -output_program: .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xD000 JMP AX + +.ORG 0xFFFF +DB 0x00 ;Make sure a full 64KiB image diff --git a/boot_code/colored_led.asm b/boot_code/colored_led.asm index 0b41e93..e453bd0 100644 --- a/boot_code/colored_led.asm +++ b/boot_code/colored_led.asm @@ -1,6 +1,4 @@ -INCLUDE dos_layer.asm - -.org 0x100 +.org 0xE000 mov sp,#STACK MAIN_LOOP: @@ -19,13 +17,14 @@ out byte #0xB0 MOV SI,#RESERVED MOV DI,#RESERVED MOV AL,#0x68 ; 'h' -STOSB -MOV AL,#0x00 -MOV AL,[SI] +#STOSB +#MOV AL,#0x00 +#MOV AL,[SI] -MOV AH,#0x02 -MOV DL,AL -INT #0x21 +#MOV AH,#0x02 +#MOV DL,AL +#INT #0x21 +out byte #0xA5 MOV AL,#0x65 out byte #0xA5 @@ -49,13 +48,18 @@ JNZ DELAY21 MOV AL,#0x00 out byte #0xB0 -MOV AX,#0x0100 +MOV AX,#0xE000 JMP AX RESERVED: DB 0x48 ; 'H' -.BLKB 200 +.BLKB 100 STACK: +#INCLUDE dos_layer.asm + .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xE000 JMP AX + +.ORG 0xFFFF +DB 0x00 ;Make sure a full 64KiB image diff --git a/boot_code/dos_layer.asm b/boot_code/dos_layer.asm index f27ef3b..853c5ec 100644 --- a/boot_code/dos_layer.asm +++ b/boot_code/dos_layer.asm @@ -1,7 +1,3 @@ -.ORG 0x84 ; INT 21 -DW 0xFFFF ; Code Segment -DW PRINT_INT_HANDLE ; Program Counter - PRINT_INT_HANDLE: push AX CMP AH,#0x02 @@ -14,3 +10,15 @@ MOV AL,DL out byte #0xA5 POP AX iret + +INIT_INT_VECT_TABLE: +push AX +push DI +MOV DI,#0x0084 +MOV AX,#0xFFFF +STOSW +MOV AX,#PRINT_INT_HANDLE +STOSW +POP DI +POP AX +RET diff --git a/boot_code/fibonacci.asm b/boot_code/fibonacci.asm index 8c879e2..f24dc01 100644 --- a/boot_code/fibonacci.asm +++ b/boot_code/fibonacci.asm @@ -1,8 +1,8 @@ -INCLUDE dos_layer.asm -org 0x100 +org 0xF000 mov sp,#STACK +call INIT_INT_VECT_TABLE MOV AX,#0x1 MOV BX,#0x1 @@ -26,6 +26,7 @@ MOV DL,#0x0a INT #0x21 hlt +INCLUDE dos_layer.asm .BLKB 200 @@ -33,6 +34,6 @@ STACK: INCLUDE helpers.asm .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xF000 JMP AX diff --git a/boot_code/gnome_sort.asm b/boot_code/gnome_sort.asm index 1918a01..c66690c 100644 --- a/boot_code/gnome_sort.asm +++ b/boot_code/gnome_sort.asm @@ -1,8 +1,8 @@ -INCLUDE dos_layer.asm -.org 0x100 +.org 0xF000 mov sp,#STACK MOV SI,#DATA +call INIT_INT_VECT_TABLE GNOME_SORT: CMP SI,#DATA+23 @@ -37,6 +37,7 @@ MOV DL,#0x0a INT #0x21 hlt +INCLUDE dos_layer.asm DATA: DB 0x51, 0x17, 0x37, 0x5d, 0x06, 0x3f, 0x51, 0x8b DB 0xa5, 0x33, 0x54, 0xdf, 0xae, 0xee, 0x3a, 0x18 @@ -48,6 +49,8 @@ STACK: INCLUDE helpers.asm .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xF000 JMP AX +.ORG 0xFFFF +DB 0x00 ;Make sure a full 64KiB image diff --git a/boot_code/pipeline_ideal.asm b/boot_code/pipeline_ideal.asm index 6ef3a20..2acf319 100644 --- a/boot_code/pipeline_ideal.asm +++ b/boot_code/pipeline_ideal.asm @@ -1,4 +1,4 @@ -org 0x100 +org 0xF000 inc ax inc bx inc ax @@ -102,5 +102,5 @@ inc bx hlt .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xF000 JMP AX diff --git a/common.mk b/common.mk index 01fc0a1..a445d2e 100644 --- a/common.mk +++ b/common.mk @@ -39,7 +39,9 @@ ifeq "${QUIET}" "1" QUIET_DFU_SUFFIX = @echo ' DFU-SUFFIX '$@; QUIET_DFU_UTIL = @echo ' DFU-UTIL '$<; - QUIET_CLEAN = @printf ' CLEAN %s\n' $1; + QUIET_DOWNLOAD = @echo ' DOWNLOAD '$@; + + QUIET_CLEAN = @echo ' CLEAN '$1; QUIET_VERILATOR_RUN = @printf ' %s %s\n' $1 $2; Q = @ MAKEOPTS=--no-print-directory @@ -54,6 +56,13 @@ run: $(subst .txt,.run,${BOOT_CODE}) wave: $(subst .txt,.wave,${BOOT_CODE}) disas: $(subst .txt,.disas,${BOOT_CODE}) +# Assembling code +%.stxt: %.bin + ${Q}dd if=/dev/zero bs=1 count=2048 of="$(subst .bin,.stage,$<)" status=none + ${Q}dd if="$<" bs=1 skip=63488 of="$(subst .bin,.stage,$<)" conv=notrunc,nocreat status=none + ${Q}xxd -ps -c 2 "$(subst .bin,.stage,$<)" > "$@" + ${Q}rm "$(subst .bin,.stage,$<)" + # Assembling code %.txt:%.bin ${Q}dd if=/dev/zero bs=1 count=65536 of="$(subst .bin,.stage,$<)" status=none @@ -61,6 +70,7 @@ disas: $(subst .txt,.disas,${BOOT_CODE}) ${Q}xxd -ps -c 2 "$(subst .bin,.stage,$<)" > "$@" ${Q}rm "$(subst .bin,.stage,$<)" + ifeq "${NO_ASM}" "0" %.bin:%.asm ${QUIET_AS} diff --git a/system/Makefile b/system/Makefile index 495b679..25a9a71 100644 --- a/system/Makefile +++ b/system/Makefile @@ -46,14 +46,14 @@ VERILATOR_OPTS += -x-assign fast --x-initial fast # COMPILING ${SYSTEM_VVP} : ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${EVENT_SIM_TESTBENCH} ${QUIET_IVERILOG} - ${Q}iverilog -g2012 -DBUILTIN_RAM=32768 -D CALCULATE_IPC -D OUTPUT_JSON_STATISTICS -o "$@" ${TOP_LEVEL_SOURCE} ${SOURCES} ${EVENT_SIM_TESTBENCH} + ${Q}iverilog -g2012 -D CALCULATE_IPC -D OUTPUT_JSON_STATISTICS -o "$@" ${TOP_LEVEL_SOURCE} ${SOURCES} ${EVENT_SIM_TESTBENCH} ${VERILATOR_BIN}: ${VERILATOR_BIN}.mk ${Q}make ${MAKEOPTS} OPT_FAST="-O2 -march=native -mtune=native" -C obj_dir -f ../verilator_makefile Vsystem ${VERILATOR_BIN}.mk: ${VERILATOR_TESTBENCH} ${TOP_LEVEL_SOURCE} ${SOURCES} ${INCLUDES} ${QUIET_VERILATOR} - ${Q}verilator -DBUILTIN_RAM=32768 -UNOT_FULL -DCALCULATE_IPC -DOUTPUT_JSON_STATISTICS ${VERILATOR_OPTS} $^ + ${Q}verilator -DCALCULATE_IPC -DOUTPUT_JSON_STATISTICS ${VERILATOR_OPTS} $^ include fpga_config/${FPGA_BOARD}/config.mk @@ -69,22 +69,23 @@ endif ECP5_TARGETS=synth_ecp5.json synth_ecp5_out.config synth_ecp5.bit synth_ecp5.dfu synth_pnr_report.json ECP5_TARGETS+=abc.history # created from yosys -EXTRA_SYNTHESIS_SOURCES=peripherals/I2C_driver.v peripherals/ascii_to_HD44780_driver.v peripherals/pcf8574_for_HD44780.v +EXTRA_SYNTHESIS_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 +EXTERNAL_IP_SOURCES=external_ip/litedram_core_ecp5_phy.v simplified_ucode.txt:ucode.txt ${Q}tr 'x' '0' < $^ | sed 's@//.*@@' | grep ^@ |sort | sed 's/.* .//;s/ $$//' | tr -d _ > $@ #TODO: we are relying on yosys to trim the input program txt file and hope its enough for the whole program... -synth_ecp5.json: ${SOURCES} ${TOP_LEVEL_SOURCE} fpga_config/${FPGA_BOARD}/fpga_top.v ${EXTRA_SYNTHESIS_SOURCES} ${INCLUDES} ../boot_code/brainfuck_compiled.txt simplified_ucode.txt +synth_ecp5.json: ${SOURCES} fpga_config/${FPGA_BOARD}/fpga_top.v ${EXTRA_SYNTHESIS_SOURCES} ${EXTERNAL_IP_SOURCES} ${INCLUDES} ../boot_code/bios.stxt simplified_ucode.txt ${QUIET_YOSYS} - ${Q} yosys -q -D BUILTIN_RAM=2048 -D NOT_FULL -p 'read -sv '"${SOURCES} ${TOP_LEVEL_SOURCE} fpga_config/${FPGA_BOARD}/fpga_top.v ${EXTRA_SYNTHESIS_SOURCES} ; synth_ecp5 -json $@ -abc9 -top fpga_top" + ${Q} yosys -q -p 'read_verilog -defer -noautowire -sv '"${SOURCES} fpga_config/${FPGA_BOARD}/fpga_top.v ${EXTRA_SYNTHESIS_SOURCES} ${EXTERNAL_IP_SOURCES}; attrmap -tocase keep -imap keep="true" keep=1 -imap keep="false" keep=0 -remove keep=0; synth_ecp5 -json $@ -abc9 -top fpga_top" RANDOM :::= $(shell seq 1 200|sort -R|head -n1) synth_ecp5_out.config:synth_ecp5.json ${QUIET_NEXTPNR} ${Q}printf '\e[1;30mNotice: nextpnr rng seed is : %s\e[0m\n' "${RANDOM}" - ${Q} nextpnr-ecp5 --seed ${RANDOM} --Werror -q --json $< --textcfg $@.1 ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --report=synth_pnr_report.json + ${Q} nextpnr-ecp5 --threads 5 --timing-allow-fail --seed ${RANDOM} --Werror -q --json $< --textcfg $@.1 ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --speed 8 --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --report=synth_pnr_report.json ${Q}../tools/parse_nextpnr_stats.sh --brief synth_pnr_report.json ${Q}mv "$@.1" "$@" @@ -103,8 +104,15 @@ upload_orangecrab:synth_ecp5.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' +NEXTPNR_SEED=186 + nextpnr-gui: synth_ecp5.json - ${Q} nextpnr-ecp5 --json $< ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --gui + ${QUIET_NEXTPNR} + ${Q} nextpnr-ecp5 --seed ${NEXTPNR_SEED} --json $< ${NEXTPNR_ECP5_DEV} --package ${ECP5_PACKAGE} --speed 8 --lpf fpga_config/${FPGA_BOARD}/pin_constraint.pcf --gui + +external_ip/litedram_core_ecp5_phy.v: + ${QUIET_DOWNLOAD} + ${Q}../tools/gen_litedram.sh "$@" upload: upload_orangecrab diff --git a/system/biu.v b/system/biu.v index 8715237..838968d 100644 --- a/system/biu.v +++ b/system/biu.v @@ -46,6 +46,7 @@ module BIU ( /**************** OUTSIDE WORLD ****************/ /* */ ,output wire [19:0] external_address_bus /* */ ,input [15:0] external_data_bus_read,output [15:0] external_data_bus_write,output reg read, output reg write,output reg BHE,output reg IOMEM + /* */ ,input wait_state /**************** OUTPUT TO DE ****************/ /* */ ,output reg [31:0] INSTRUCTION, output reg VALID_INSTRUCTION, output reg [15:0] INSTRUCTION_LOCATION @@ -105,7 +106,7 @@ always @(posedge clock) begin FIFO_end <= `L1_CACHE_SIZE'b0; end else if ( jump_req ) begin FIFO_start <= FIFO_end ; - INSTRUCTION_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; + INSTRUCTION_ADDRESS <= { 4'hF , ADDRESS_INPUT }; INSTRUCTION_LOCATION <= ADDRESS_INPUT; func <= 1; if (biu_state==`BIU_READ) @@ -115,6 +116,8 @@ always @(posedge clock) begin FIFO_start <= FIFO_start + {{`L1_CACHE_SIZE-3{1'b0}},Isize}; /* verilator lint_on BLKSEQ */ INSTRUCTION_LOCATION <= INSTRUCTION_LOCATION + {13'd0,Isize}; + end else if (wait_state==1)begin + // nothing... end else begin case(biu_state) `BIU_HALT: begin @@ -122,14 +125,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 */ if (write_request) begin func<=0; - DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; + DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT }; IOMEM <= MEM_OR_IO; biu_state <= (Wbit==0) ? `BIU_PUT_BYTE : (ADDRESS_INPUT[0:0]?`BIU_PUT_UNALIGNED_16BIT_DATA:`BIU_PUT_ALIGNED_16BIT_DATA) ; - INSTRUCTION_ADDRESS <= {4'b0,INSTRUCTION_LOCATION} ; + INSTRUCTION_ADDRESS <= {4'hF,INSTRUCTION_LOCATION} ; FIFO_end<=FIFO_start; end else if ( read_request ) begin func<=0; - DATA_ADDRESS <= { 4'b0 , ADDRESS_INPUT }; + DATA_ADDRESS <= { 4'hF , ADDRESS_INPUT }; IOMEM <= MEM_OR_IO; read <= 0; BHE <= 0; @@ -275,7 +278,7 @@ always @(posedge clock) begin FIFO_end <= `L1_CACHE_SIZE'b0; /* verilator lint_on BLKSEQ */ biu_state <= `BIU_NEXT_ACTION; - INSTRUCTION_ADDRESS <= 20'h0FFF0; + INSTRUCTION_ADDRESS <= 20'hFFFF0; INSTRUCTION_LOCATION <= 16'hFFF0; VALID_DATA <= 0; sane<=1; diff --git a/system/boot_code.asm b/system/boot_code.asm index 1cfea54..d7fc602 100644 --- a/system/boot_code.asm +++ b/system/boot_code.asm @@ -1,8 +1,4 @@ -.ORG 0x84 ; INT 21 -DW 0xFFFF ; Code Segment -DW PRINT_INT_HANDLE ; Program Counter - -.ORG 0x0100 +.ORG 0xFF00 start: MOV SP,#STACK MOV AX,#0x0000 @@ -26,20 +22,14 @@ dec cx cmp CX,#0x00 MOV CH,#0x9A inw #0x20 -CMP AL,#0xCD +CMP AX,#0xABCD jz WAZZ mov al,#'0 out byte #0xA5 hlt WAZZ: -CMP AH,#0xAB -jz WAZZ2 -mov al,#'0 -out byte #0xA5 -hlt -WAZZ2: mov al,#'1 -outb #0xA5 +out byte #0xA5 hlt TEST_: ADD AX,#0xDEAD @@ -57,5 +47,5 @@ iret STACK: .ORG 0xFFF0 -MOV AX,#0x0100 +MOV AX,#0xFF00 JMP AX diff --git a/system/config.v b/system/config.v index 3e8e74f..a475d49 100644 --- a/system/config.v +++ b/system/config.v @@ -46,15 +46,6 @@ * . : ... */ `define L1_CACHE_SIZE 4 -//// These are usually set at build time -// -// /* This is the "virtual" synthesised ram, so for example on an FPGA -// * This would be made inside the fabric of the fpga. */ -// `define BUILTIN_RAM 512 -// ////// ATTENTION: PLEASE IF BUILTIN_RAM DOESN'T COVER THE ENTIRE (CURRENTLY) -// // 16 BIT RANGE, I.E. ISN'T 32768, PLEASE SET THE FOLLOWING FLAG -// `define NOT_FULL - /********** Internal **********/ `ifdef SYNTHESIS diff --git a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v index 1b4afdc..88db6cb 100644 --- a/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v +++ b/system/fpga_config/OrangeCrab_r0.2.1/fpga_top.v @@ -18,10 +18,12 @@ along with this program. If not, see . */ `include "error_header.v" +`ifdef OUTPUT_JSON_STATISTICS +`include "config.v" +`endif module fpga_top( input clk48, - input user_button, // output reset_n, @@ -29,23 +31,68 @@ module fpga_top( output rgb_led0_g, output rgb_led0_b, + 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 gpio_0,/*sda*/ output gpio_1 /*scl*/ ); +assign ddram_a[15:13] = 3'b0; +assign ddram_vccio = 6'd63; +assign ddram_gnd = 2'd0; + 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=clk48; -system system( - /* MISC */ CPU_SPEED,reset - /* MEMORY / IO */ ,address_bus,data_bus_read,data_bus_write,BHE,rd,wr,IOMEM,HALT,ERROR +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 ); +`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 reg [2:0]rgb_led_color; assign rgb_led0_r=rgb_led_color[0]; assign rgb_led0_g=rgb_led_color[1]; @@ -80,7 +127,7 @@ reg [1:0] state=0; always @(posedge counter[15]) begin if(user_button==0) - state=2'b00; + state<=2'b00; case (state) 2'b00:begin reset<=0; @@ -95,7 +142,6 @@ always @(posedge counter[15]) begin endcase end - //------------------------------------------// // Cache to allow the slow display to have a // chance to keep up with the relentless CPU @@ -135,6 +181,189 @@ 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 : Wishbone_driver_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)); + +/// DDR3 Controller + +wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked; + +wire [31:0] ddr3_read_data; +wire [31:0] ddr3_write_data; + +reg [15:0]DDR3_data_bus_read; + +assign ddr3_write_data={16'd0,data_bus_write}; + +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), + .data_bus_in(data_bus_write), + .data_bus_out(data_bus_read_DDR3), + .wait_state(wait_state), + .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; + +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), + .rst(!reset), + + ////// DDR3 INTERFACE ////// + .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), + + /////// 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), + .pll_locked(ddr3_pll_locked), + //output wire 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) +); + // Display driver wire ascii_data_ready; diff --git a/system/memory.v b/system/memory.v index cabbbef..b655a80 100644 --- a/system/memory.v +++ b/system/memory.v @@ -19,10 +19,24 @@ /* This warning is because we don't use the full address bus. */ /* verilator lint_off UNUSEDSIGNAL */ -module doublemem(input [19:0] address,output [15:0] cpu_read_data ,input [15:0] cpu_write_data,input rd,input wr,input BHE,input cs,input clock); +module doublemem + #( + parameter RAM_SIZE_IN_BYTES, + parameter ADDRESS_WIDTH=$clog2(RAM_SIZE_IN_BYTES) + ) + ( input [ ADDRESS_WIDTH-1 : 0 ] address, + output [15:0] cpu_read_data, + input [15:0] cpu_write_data, + input rd, + input wr, + input BHE, + input cs, + input clock + ); /* verilator lint_on UNUSEDSIGNAL */ -reg [15:0] memory [0:`BUILTIN_RAM]; +reg [15:0] memory [0:(RAM_SIZE_IN_BYTES/2)-1]; + initial begin `ifndef YOSYS @@ -31,39 +45,26 @@ initial begin $display("No boot code specified. Please add +BOOT_CODE= to your vvp args"); $finish; end - $readmemh(boot_code, memory,0,`BUILTIN_RAM-1); + $readmemh(boot_code, memory,0,32767); `else //TODO: don't have it hard coded - $readmemh("../boot_code/brainfuck_compiled.txt", memory,0,`BUILTIN_RAM-1); -`endif - -`ifdef NOT_FULL - jump_mem[0]=16'hB800; - jump_mem[1]=16'h01ff; - jump_mem[2]=16'hE000; + $readmemh("../boot_code/bios.stxt", memory,0,(RAM_SIZE_IN_BYTES/2)-1); // 2KiB `endif end -`ifndef NOT_FULL -assign cpu_read_data[7:0] = !address[0:0] & !rd & !cs ? memory[address[16:1]][15:8] : 8'hz; -assign cpu_read_data[15:8] = !BHE & !rd & !cs ? memory[address[16:1]][7:0] : 8'hz; -`else -reg[15:0] jump_mem [0:4'h7]; +assign cpu_read_data[7:0] = !address[0:0] & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][15:8] : 8'hz; -assign cpu_read_data[7:0] = !address[0:0] & !rd & !cs ? (address[15:4]==12'b111111111111 ? jump_mem[address[3:1]][15:8]:memory[address[16:1]][15:8]) : 8'hz; +assign cpu_read_data[15:8] = !BHE & !rd & !cs ? memory[address[ADDRESS_WIDTH-1:1]][ 7:0] : 8'hz; -assign cpu_read_data[15:8] = !BHE & !rd & !cs ? (address[15:4]==12'b111111111111 ? jump_mem[address[3:1]][7:0]:memory[address[16:1]][7:0]) : 8'hz; - -`endif always @(posedge clock) begin if( cs == 0 && wr == 0) begin if(BHE==0) - memory[address[16:1]][7:0]<=cpu_write_data[15:8]; + memory[address[ADDRESS_WIDTH-1:1]][7:0]<=cpu_write_data[15:8]; if(address[0]==0) - memory[address[16:1]][15:8]<=cpu_write_data[7:0]; + memory[address[ADDRESS_WIDTH-1:1]][15:8]<=cpu_write_data[7:0]; end end diff --git a/system/peripherals/Wishbone_IO_driver.v b/system/peripherals/Wishbone_IO_driver.v new file mode 100644 index 0000000..42722ee --- /dev/null +++ b/system/peripherals/Wishbone_IO_driver.v @@ -0,0 +1,127 @@ +/* Wishbone_driver.v - Implements a classic wishbone master + + This file is part of the 9086 project. + + Copyright (c) 2023 Efthymios Kritikos + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +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 senario 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 diff --git a/system/peripherals/Wishbone_memory_driver.v b/system/peripherals/Wishbone_memory_driver.v new file mode 100644 index 0000000..adb1f45 --- /dev/null +++ b/system/peripherals/Wishbone_memory_driver.v @@ -0,0 +1,149 @@ +/* Wishbone_driver.v - Implements a classic wishbone master that maps directly in memory space + + This file is part of the 9086 project. + + Copyright (c) 2023 Efthymios Kritikos + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +module Wishbone_memory_driver ( + input wire clock, + input wire reset_n, + + input wire [19:0] address, + input wire [15:0] data_bus_in, + output reg [15:0] data_bus_out, + output reg wait_state, + input read_n, + input write_n, + input chip_select_n, + + input wire wb_mem_ack, + output wire [24:0] wb_mem_adr, + output wire 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, + input wire wb_mem_err, + output wire [3:0] wb_mem_sel, + output wire wb_mem_stb, + output wire wb_mem_we +); + +reg WISHBONE_ACTIVE_CYCLE=1'b0; +/* verilator lint_off UNUSEDSIGNAL */ +wire WISHBONE_ERROR_IN; +/* verilator lint_on UNUSEDSIGNAL */ +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 [15:0]WISHBONE_DATA_WRITE; + +assign WISHBONE_ACK_IN=wb_mem_ack; +assign wb_mem_adr={5'd0,address}; +assign WISHBONE_ERROR_IN=wb_mem_err; +assign wb_mem_sel=WISHBONE_SELECT; +assign wb_mem_stb=WISHBONE_VALID_TRANSFER; +assign wb_mem_cyc=WISHBONE_ACTIVE_CYCLE; +assign wb_mem_we=WISHBONE_WRITE; +assign WISHBONE_DATA_WRITE=wb_mem_data_r[15:0]; +assign wb_mem_data_w=WISHBONE_DATA_READ; + +wire CYCLE_END=(WISHBONE_ACK_IN==1'b1);//||WISHBONE_ERROR_IN==1'b1); + +reg [3:0] state; + +always @(*) begin + wait_state=0; + if(reset_n==1) begin + case(state) + 4'd0:begin + if( chip_select_n && ((!read_n)||(!write_n)) )begin + wait_state=1; + end else begin + wait_state=0; + end + end + 4'd1:begin + wait_state=1; + end + 4'd2:begin + wait_state=1; + end + 4'd3:begin + wait_state=1; + end + 4'd4:begin + wait_state=0; + end + default:begin + end + endcase + end else begin + wait_state=0; + end +end + +always @(posedge clock)begin + if(reset_n==0) + state<=0; + else begin + case(state) + 4'd0:begin + if( chip_select_n && ((!read_n)||(!write_n)) )begin + state<=4'd1; + end + end + 4'd1:begin + WISHBONE_ACTIVE_CYCLE<=1; + WISHBONE_VALID_TRANSFER<=1; + WISHBONE_SELECT<=4'hF; + WISHBONE_WRITE<=read_n; + if(read_n)begin + state<=4'd2; + WISHBONE_DATA_READ<={16'h0,data_bus_in}; + end else + state<=4'd3; + end + 4'd2:begin + if(CYCLE_END==1'b1)begin + state<=4'd4; + WISHBONE_ACTIVE_CYCLE<=0; + WISHBONE_VALID_TRANSFER<=0; + end + end + 4'd3:begin + if(CYCLE_END==1'b1)begin + data_bus_out<=WISHBONE_DATA_WRITE[15:0]; + state<=4'd4; + WISHBONE_ACTIVE_CYCLE<=0; + WISHBONE_VALID_TRANSFER<=0; + end + end + 4'd4:begin + if(read_n&&write_n) + state<=4'd0; + end + default:begin + state<=4'd0; + end + endcase + end +end + +endmodule diff --git a/system/processor.v b/system/processor.v index 6918c5c..7f8ddfc 100644 --- a/system/processor.v +++ b/system/processor.v @@ -32,7 +32,7 @@ module processor ( /* MISC */ input clock, input reset, output wire HALT,output [`ERROR_BITS-1:0] ERROR - /* MEMORY / IO */ ,output [19:0] external_address_bus, input [15:0] external_data_bus_read, output [15:0] external_data_bus_write,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 /* STATISTICS */ ,output wire new_instruction @@ -111,6 +111,7 @@ BIU BIU( /**************** OUTSIDE WORLD ****************/ /* */ ,external_address_bus /* */ ,external_data_bus_read,external_data_bus_write,read,write,BHE,IOMEM + /* */ ,wait_state /**************** OUTPUT TO DE ****************/ /* */ ,IF2DE_INSTRUCTION,VALID_INSTRUCTION,INSTRUCTION_LOCATION diff --git a/system/system.v b/system/system.v index 6e69924..ab64ccc 100644 --- a/system/system.v +++ b/system/system.v @@ -37,10 +37,11 @@ wire [15:0]data_bus_read_CPU,data_bus_write_CPU; assign data_bus_read_CPU=(IOMEM==0)?data_bus_read_RAM:data_bus_IO; assign data_bus_write=data_bus_write_CPU; +wire wait_state=1'b0; processor p( /* MISC */ clock,reset,HALT,ERROR - /* MEMORY / IO */ ,address_bus,data_bus_read_CPU,data_bus_write_CPU,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 /* STATISTICS */ ,new_instruction `endif @@ -51,7 +52,7 @@ processor p( wire [15:0] data_bus_read_RAM; -doublemem sysmem(address_bus,data_bus_read_RAM,data_bus_write_CPU,rd,wr,BHE,IOMEM,clock); +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; diff --git a/tools/gen_litedram.sh b/tools/gen_litedram.sh new file mode 100755 index 0000000..4beec7a --- /dev/null +++ b/tools/gen_litedram.sh @@ -0,0 +1,92 @@ +#!/bin/sh +set -eu + +SOURCE_CODE_URL=https://github.com/enjoy-digital/litedram/archive/refs/tags/2023.08.tar.gz +SOURCE_MD5_SUM=afc2208c08e60994d126c445574960da + +if [ "$#" = 0 ] || echo "$1" | grep '^-' > /dev/null +then + echo This scripts generates a verilog file from the Migen project litedram + echo It is currently hardcoded for the ECP5 PHY + echo The provided file system/external_ip/litedram_core_ecp5_phy.v is the output of this program *BUT MODIFIED* + echo + echo Usage: + echo \ \ \ "$0" \ + + if ! [ "$#" = 0 ] + then + if ! [ "$1" = "--help" ] && ! [ "$1" = "-h" ] + then + exit 1 + else + exit 0 + fi + else + exit 1 + fi +fi + +TEMP_DIR=$(mktemp -d) +trap 'rm -rf -- "$TEMP_DIR"' EXIT +CUR_DIR=$(pwd) + +if echo "$1" | grep '^/' > /dev/null +then + OUT_FILE=$1 +else + OUT_FILE="${CUR_DIR}/$1" +fi + +cd "$TEMP_DIR" +#echo Downloading source code... + +wget --output-document=source.tar.gz --quiet "$SOURCE_CODE_URL" + +if [ "$(md5sum source.tar.gz)" != "${SOURCE_MD5_SUM} source.tar.gz" ] +then + #echo source doesn\'t match md5 sum + exit 1 +fi + +#echo extracting the source... +tar xvf source.tar.gz > source_dir + +SOURCE_DIR=$(head -n 1 source_dir) +rm source_dir + +#echo patching the source... + +#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 + + +#echo building the file... + +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/ + +if ! python3 gen.py ../../../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 + +#echo patching source file... + +#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 + +cp build/gateware/litedram_core.v "$OUT_FILE" + +#echo File built correctly!