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)

This commit is contained in:
(Tim) Efthimis Kritikos 2023-12-03 19:24:12 +00:00
parent f1dc9d8a59
commit 63ea29e399
26 changed files with 1158 additions and 118 deletions

2
.gitignore vendored
View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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})

395
boot_code/bios.asm Normal file
View File

@ -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

View File

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

View File

@ -17,6 +17,8 @@
; You should have received a copy of the GNU General Public License
; along with this program. If not, see <http://www.gnu.org/licenses/>.
; 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

View File

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

View File

@ -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

View File

@ -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

View File

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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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}

View File

@ -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

View File

@ -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;

View File

@ -1,8 +1,4 @@
.ORG 0x84 ; INT 21
DW 0xFFFF ; Code Segment
DW PRINT_INT_HANDLE ; Program Counter
.ORG 0x0100
.ORG 0xFF00
start:
MOV SP,#STACK
MOV AX,#0x0000
@ -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

View File

@ -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

View File

@ -18,10 +18,12 @@
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,
@ -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;

View File

@ -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=<path> 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

View File

@ -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 <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 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

View File

@ -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 <http://www.gnu.org/licenses/>. */
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

View File

@ -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

View File

@ -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;

92
tools/gen_litedram.sh Executable file
View File

@ -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" \<output verilog file\>
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!