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.
This commit is contained in:
parent
1d9be44c5a
commit
1966ab78b4
13
Makefile
13
Makefile
@ -21,7 +21,7 @@ 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} boot_code/colored_led.txt boot_code/bios.stxt
|
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=.
|
PRINT_PATH_PREFIX=.
|
||||||
|
|
||||||
NO_ASM=1
|
NO_ASM=1
|
||||||
@ -55,11 +55,16 @@ mrproper: clean
|
|||||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code mrproper
|
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code mrproper
|
||||||
|
|
||||||
.PHONY: upload_bitstream
|
.PHONY: upload_bitstream
|
||||||
upload_bitstream: boot_code/bios.stxt
|
upload_bitstream: boot_code/i2c_bootloader.stxt
|
||||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system upload_bitstream
|
${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
|
.PHONY: fpga_sim
|
||||||
fpga_sim: boot_code/bios.stxt
|
fpga_sim: boot_code/i2c_bootloader.stxt
|
||||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system fpga_sim
|
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system fpga_sim
|
||||||
|
|
||||||
.PHONY: help
|
.PHONY: help
|
||||||
@ -76,6 +81,8 @@ help:
|
|||||||
@echo 'Synthesis targets:'
|
@echo 'Synthesis targets:'
|
||||||
@echo ' upload_bitstream - Build a bitstream for the board selected in'
|
@echo ' upload_bitstream - Build a bitstream for the board selected in'
|
||||||
@echo ' common.mk and upload it if possible'
|
@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_sim - Simulate the SoC that gets build for the configured'
|
||||||
@echo ' fpga board'
|
@echo ' fpga board'
|
||||||
@echo ''
|
@echo ''
|
||||||
|
@ -18,7 +18,7 @@
|
|||||||
|
|
||||||
PRINT_PATH_PREFIX=./
|
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_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
|
SOURCE_SHORT=bios.asm i2c_bootloader.asm
|
||||||
BINARIES=$(subst .asm,.txt,${SOURCE_FULL}) $(subst .asm,.stxt,${SOURCE_SHORT})
|
BINARIES=$(subst .asm,.txt,${SOURCE_FULL}) $(subst .asm,.stxt,${SOURCE_SHORT})
|
||||||
BUILD_FILES=${BINARIES}
|
BUILD_FILES=${BINARIES}
|
||||||
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE_FULL} ${SOURCE_SHORT})
|
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE_FULL} ${SOURCE_SHORT})
|
||||||
@ -33,6 +33,7 @@ brainfuck_compiled.bin: brainfuck_compiler_v1.asm hello_9086.bf.asm dos_layer.as
|
|||||||
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
|
colored_led.bin: dos_layer.asm
|
||||||
bios.bin: LiteDram_init.asm brainfuck_compiler_v1.asm hello_9086.bf.asm 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
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
org 0x100
|
org 0x100
|
||||||
output_program:
|
output_program:
|
||||||
|
|
||||||
org 0xD000
|
org 0xC000
|
||||||
mov sp,#SMALL_STACK
|
mov sp,#SMALL_STACK
|
||||||
call INIT_INT_VECT_TABLE
|
call INIT_INT_VECT_TABLE
|
||||||
INCLUDE brainfuck_compiler_v1.asm
|
INCLUDE brainfuck_compiler_v1.asm
|
||||||
@ -15,7 +15,7 @@ INCLUDE mandelbrot.bf.asm
|
|||||||
|
|
||||||
|
|
||||||
.ORG 0xFFF0
|
.ORG 0xFFF0
|
||||||
MOV AX,#0xD000
|
MOV AX,#0xC000
|
||||||
JMP AX
|
JMP AX
|
||||||
|
|
||||||
.ORG 0xFFFF
|
.ORG 0xFFFF
|
||||||
|
118
boot_code/i2c_bootloader.asm
Normal file
118
boot_code/i2c_bootloader.asm
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
.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: inw #0x62
|
||||||
|
;test al,#0x01
|
||||||
|
;jnz wait_send
|
||||||
|
|
||||||
|
mov ax,#0x1FFE
|
||||||
|
aa:
|
||||||
|
dec ax
|
||||||
|
jnz aa
|
||||||
|
|
||||||
|
mov bx,#OK_loading_txt
|
||||||
|
call print
|
||||||
|
|
||||||
|
|
||||||
|
;############ READ 20% ##################
|
||||||
|
|
||||||
|
mov bx,#0xD000
|
||||||
|
mov di,#0x0000
|
||||||
|
rom_read_loop:
|
||||||
|
mov al,#0x05 ; Read, 8bit, ignore ack
|
||||||
|
outb #0x63
|
||||||
|
|
||||||
|
mov al,#0x00
|
||||||
|
outb #0x60
|
||||||
|
|
||||||
|
mov ax,#0x1FFE
|
||||||
|
aa2:
|
||||||
|
dec ax
|
||||||
|
jnz aa2
|
||||||
|
|
||||||
|
inw #0x60
|
||||||
|
STOSB
|
||||||
|
|
||||||
|
cmp di,#0x2999
|
||||||
|
jz print_20
|
||||||
|
cmp di,#0x5333
|
||||||
|
jz print_40
|
||||||
|
cmp di,#0x7CCC
|
||||||
|
jz print_60
|
||||||
|
cmp di,#0xA666
|
||||||
|
jz print_80
|
||||||
|
|
||||||
|
back:dec bx
|
||||||
|
jnz rom_read_loop
|
||||||
|
|
||||||
|
|
||||||
|
MOV AX,#0xC000
|
||||||
|
JMP AX
|
||||||
|
|
||||||
|
print_20:
|
||||||
|
mov bx,#twenty_prc_txt
|
||||||
|
call print
|
||||||
|
jmp back
|
||||||
|
|
||||||
|
print_40:
|
||||||
|
mov bx,#forty_prc_txt
|
||||||
|
call print
|
||||||
|
jmp back
|
||||||
|
|
||||||
|
print_60:
|
||||||
|
mov bx,#sixty_prc_txt
|
||||||
|
call print
|
||||||
|
jmp back
|
||||||
|
|
||||||
|
print_80:
|
||||||
|
mov bx,#eighty_prc_txt
|
||||||
|
call print
|
||||||
|
jmp back
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
load_i2c_txt: .ASCII 'Read I2C EEPROM:\0'
|
||||||
|
OK_loading_txt: .ASCII 'OK\nLoading rom 0%\r\0'
|
||||||
|
twenty_prc_txt: .ASCII 'Loading rom 20%\r\0'
|
||||||
|
forty_prc_txt: .ASCII 'Loading rom 40%\r\0'
|
||||||
|
sixty_prc_txt: .ASCII 'Loading rom 60%\r\0'
|
||||||
|
eighty_prc_txt: .ASCII 'Loading rom 80%\r\0'
|
||||||
|
|
||||||
|
.ORG 0xFFF0
|
||||||
|
MOV AX,#0xF800
|
||||||
|
JMP AX
|
||||||
|
|
||||||
|
.ORG 0xFFFF
|
||||||
|
DB 0x00 ;Make sure a full 64KiB image
|
@ -47,6 +47,7 @@ ifeq "${QUIET}" "1"
|
|||||||
QUIET_ECPPACK = @echo ' ECPPACK '${PRINT_PATH_PREFIX}$@;
|
QUIET_ECPPACK = @echo ' ECPPACK '${PRINT_PATH_PREFIX}$@;
|
||||||
QUIET_DFU_SUFFIX = @echo ' DFU-SUFFIX '${PRINT_PATH_PREFIX}$@;
|
QUIET_DFU_SUFFIX = @echo ' DFU-SUFFIX '${PRINT_PATH_PREFIX}$@;
|
||||||
QUIET_DFU_UTIL = @echo ' DFU-UTIL '${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_DOWNLOAD = @echo ' DOWNLOAD '${PRINT_PATH_PREFIX}$@;
|
||||||
|
|
||||||
|
@ -100,9 +100,9 @@ ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN}.mk: fpga_config/${
|
|||||||
${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}
|
${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
|
.PHONY: fpga_sim
|
||||||
fpga_sim fpga_sim.fst: ../boot_code/bios.stxt ${BUILD_FILES_PREFIX}/sim_${FPGA_BOARD}/${VERILATOR_FPGA_BIN} ${MICROCODE} simplified_ucode.txt
|
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,$^),$<)
|
$(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/bios.stxt" +MICROCODE="simplified_ucode.txt"
|
${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 ####
|
#### FPGA/ASIC RECIPES ####
|
||||||
@ -157,6 +157,9 @@ dfu_upload:${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.dfu
|
|||||||
${QUIET_DFU_UTIL}
|
${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'
|
${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 ####
|
#### CLEAN-UP ####
|
||||||
|
@ -15,18 +15,22 @@ FPGA_FILE_EXT=dfu
|
|||||||
# 6 is the slowest and 8 is the fastest
|
# 6 is the slowest and 8 is the fastest
|
||||||
ECP5_SPEED_GRADE=8
|
ECP5_SPEED_GRADE=8
|
||||||
|
|
||||||
|
ROM_PART_ID=24lc512
|
||||||
|
|
||||||
######## End of user configuration ########
|
######## End of user configuration ########
|
||||||
|
|
||||||
#NOT USED OUTSIDE OF HERE
|
#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
|
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_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_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/bios.stxt
|
FPGA_BOOTCODE=../boot_code/i2c_bootloader.stxt
|
||||||
|
|
||||||
|
ROM_FILE=../boot_code/brainfuck_mandelbrot.bin
|
||||||
|
|
||||||
upload_bitstream: dfu_upload
|
upload_bitstream: dfu_upload
|
||||||
|
upload_bootrom: minipro_upload
|
||||||
|
|
||||||
${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.bit:${BUILD_FILES_PREFIX}nextpnr-ecp5_${BUILD_NAME}.bit
|
${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.bit:${BUILD_FILES_PREFIX}nextpnr-ecp5_${BUILD_NAME}.bit
|
||||||
${Q}cp "$^" "$@"
|
${Q}cp "$^" "$@"
|
||||||
|
@ -193,16 +193,16 @@ end
|
|||||||
// Cache to allow the slow display to have a
|
// Cache to allow the slow display to have a
|
||||||
// chance to keep up with the relentless CPU
|
// chance to keep up with the relentless CPU
|
||||||
|
|
||||||
reg [6:0] disp_cache_start=0;
|
reg [7:0] disp_cache_start=0;
|
||||||
reg [6:0] disp_cache_end=0;
|
reg [7:0] disp_cache_end=0;
|
||||||
reg [7:0] disp_write_cache [127:0];
|
reg [7:0] disp_write_cache [255:0];
|
||||||
reg ascii_state=0;
|
reg ascii_state=0;
|
||||||
always @(posedge CPU_SPEED)begin
|
always @(posedge CPU_SPEED)begin
|
||||||
|
|
||||||
if(wr==0)begin
|
if(wr==0)begin
|
||||||
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
|
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
|
||||||
disp_write_cache[disp_cache_end]<=data_bus_write[15:8];
|
disp_write_cache[disp_cache_end]<=data_bus_write[15:8];
|
||||||
disp_cache_end<=disp_cache_end+7'd1;
|
disp_cache_end<=disp_cache_end+8'd1;
|
||||||
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
|
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
|
||||||
if(data_bus_write[0:0]==1)
|
if(data_bus_write[0:0]==1)
|
||||||
rgb_led_color<=3'b000;
|
rgb_led_color<=3'b000;
|
||||||
@ -215,7 +215,7 @@ always @(posedge CPU_SPEED)begin
|
|||||||
$write("%s" ,disp_write_cache[disp_cache_start]); // TODO: maybe simulate the i2c lcd
|
$write("%s" ,disp_write_cache[disp_cache_start]); // TODO: maybe simulate the i2c lcd
|
||||||
`endif
|
`endif
|
||||||
ascii_data<=disp_write_cache[disp_cache_start];
|
ascii_data<=disp_write_cache[disp_cache_start];
|
||||||
disp_cache_start<=disp_cache_start+7'd1;
|
disp_cache_start<=disp_cache_start+8'd1;
|
||||||
ascii_data_write_req<=1;
|
ascii_data_write_req<=1;
|
||||||
ascii_state<=1'b1;
|
ascii_state<=1'b1;
|
||||||
end
|
end
|
||||||
@ -245,12 +245,12 @@ doublemem #( .RAM_SIZE_IN_BYTES(2048) ) boot_rom
|
|||||||
/// Memory Map
|
/// Memory Map
|
||||||
|
|
||||||
assign data_bus_read = ( IOMEM == 1 ) ? data_bus_read_IO : data_bus_read_MEM ;
|
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;
|
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));
|
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 [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);
|
wire DDR3_ram_cs = (IOMEM==0)&&(address_bus[15:12]!=4'hF);
|
||||||
//
|
//
|
||||||
@ -264,7 +264,17 @@ wire DDR3_ram_cs = (IOMEM==0)&&(address_bus[15:12]!=4'hF);
|
|||||||
// 0x3F | WISHBONE |
|
// 0x3F | WISHBONE |
|
||||||
//
|
//
|
||||||
assign wishbone_cs=!((IOMEM==1)&&(address_bus[7:4] == 4'h4));
|
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
|
/// DDR3 Controller
|
||||||
|
|
||||||
wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked;
|
wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked;
|
||||||
@ -323,7 +333,7 @@ Wishbone_memory_driver Wishbone_memory_driver(
|
|||||||
.BHE(BHE),
|
.BHE(BHE),
|
||||||
.data_bus_in(data_bus_write),
|
.data_bus_in(data_bus_write),
|
||||||
.data_bus_out(data_bus_read_DDR3),
|
.data_bus_out(data_bus_read_DDR3),
|
||||||
.wait_state(wait_state),
|
.wait_state(wait_state_WBIO),
|
||||||
.read_n(rd),
|
.read_n(rd),
|
||||||
.write_n(wr),
|
.write_n(wr),
|
||||||
.chip_select_n(!(DDR3_ram_cs&&ddr3_init_done)),
|
.chip_select_n(!(DDR3_ram_cs&&ddr3_init_done)),
|
||||||
@ -341,6 +351,8 @@ Wishbone_memory_driver Wishbone_memory_driver(
|
|||||||
);
|
);
|
||||||
|
|
||||||
wire wait_state;
|
wire wait_state;
|
||||||
|
assign wait_state=wait_state_WBIO||wait_state_I2C;
|
||||||
|
wire wait_state_WBIO;
|
||||||
|
|
||||||
wire wb_ctrl_ack;
|
wire wb_ctrl_ack;
|
||||||
wire [29:0] wb_ctrl_adr;
|
wire [29:0] wb_ctrl_adr;
|
||||||
@ -422,6 +434,38 @@ litedram_core DDR3_RAM_DRIVER(
|
|||||||
.wb_ctrl_dat_w(wb_ctrl_dat_w)
|
.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;
|
||||||
|
|
||||||
|
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)
|
||||||
|
);
|
||||||
|
|
||||||
// Display driver
|
// Display driver
|
||||||
|
|
||||||
wire ascii_data_ready;
|
wire ascii_data_ready;
|
||||||
@ -448,7 +492,14 @@ ascii_to_HD44780_driver LCD_DRIVER(
|
|||||||
|
|
||||||
wire pcf_write_req,pcf_command_data,pcf_busy;
|
wire pcf_write_req,pcf_command_data,pcf_busy;
|
||||||
wire [3:0]pcf_data;
|
wire [3:0]pcf_data;
|
||||||
wire [7:0]i2c_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(
|
pcf8574_for_HD44780 PCF8574_driver(
|
||||||
.clock(I2C_SPEED),
|
.clock(I2C_SPEED),
|
||||||
@ -461,16 +512,61 @@ pcf8574_for_HD44780 PCF8574_driver(
|
|||||||
.new_backlight(1'b0),
|
.new_backlight(1'b0),
|
||||||
.backlight_update(1'b0),
|
.backlight_update(1'b0),
|
||||||
|
|
||||||
.I2C_BUSY(I2C_BUSY),
|
.DIR(DISP_DIR),
|
||||||
.I2C_SEND(I2C_SEND),
|
.I2C_BUSY(DISP_I2C_BUSY),
|
||||||
|
.I2C_TRANSACT(DISP_I2C_TRANSACT),
|
||||||
|
|
||||||
.i2c_data(i2c_data)
|
.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;
|
||||||
|
|
||||||
|
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),
|
||||||
|
|
||||||
|
////// 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),
|
||||||
|
|
||||||
|
////// 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)
|
||||||
);
|
);
|
||||||
|
|
||||||
// I2C driver
|
// I2C driver
|
||||||
|
|
||||||
wire SDA_direction;
|
wire SDA_direction;
|
||||||
wire SCL,SDA_input,SDA_output,I2C_BUSY,I2C_SEND;
|
wire SCL,SDA_input,SDA_output;
|
||||||
|
wire MULT_TO_DRIV_TRANS_WIDTH;
|
||||||
|
wire MULT_TO_DRIV_IGN_ACK;
|
||||||
|
|
||||||
I2C_driver i2c_driver(
|
I2C_driver i2c_driver(
|
||||||
.clock(I2C_SPEED),
|
.clock(I2C_SPEED),
|
||||||
@ -480,10 +576,15 @@ I2C_driver i2c_driver(
|
|||||||
.SDA_direction(SDA_direction),
|
.SDA_direction(SDA_direction),
|
||||||
.SCL(SCL),
|
.SCL(SCL),
|
||||||
|
|
||||||
.address(7'h27),
|
.address(MULT_TO_DRIV_I2C_ADDRESS),
|
||||||
.I2C_BUSY(I2C_BUSY),
|
.I2C_BUSY(MULT_TO_DRIV_I2C_BUSY),
|
||||||
.I2C_SEND(I2C_SEND),
|
.I2C_TRANSACT(MULT_TO_DRIV_I2C_TRANSACT),
|
||||||
.i2c_data(i2c_data)
|
.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)
|
||||||
);
|
);
|
||||||
|
|
||||||
`ifdef SYNTHESIS
|
`ifdef SYNTHESIS
|
||||||
|
@ -48,7 +48,7 @@ initial begin
|
|||||||
$readmemh(boot_code, memory,0,(RAM_SIZE_IN_BYTES/2)-1);
|
$readmemh(boot_code, memory,0,(RAM_SIZE_IN_BYTES/2)-1);
|
||||||
`else
|
`else
|
||||||
//TODO: don't have it hard coded
|
//TODO: don't have it hard coded
|
||||||
$readmemh("../boot_code/bios.stxt", memory,0,(RAM_SIZE_IN_BYTES/2)-1); // 2KiB
|
$readmemh("../boot_code/i2c_bootloader.stxt", memory,0,(RAM_SIZE_IN_BYTES/2)-1); // 2KiB
|
||||||
`endif
|
`endif
|
||||||
end
|
end
|
||||||
|
|
||||||
|
91
system/peripherals/CPU_to_I2C_driver_bridge.v
Normal file
91
system/peripherals/CPU_to_I2C_driver_bridge.v
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
/* 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
|
||||||
|
);
|
||||||
|
|
||||||
|
//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 <= {15'd0,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
|
@ -26,10 +26,18 @@ module I2C_driver (
|
|||||||
|
|
||||||
input wire [6:0] address,
|
input wire [6:0] address,
|
||||||
output reg I2C_BUSY=0,
|
output reg I2C_BUSY=0,
|
||||||
input wire I2C_SEND,
|
input wire I2C_TRANSACT,
|
||||||
input wire [7:0] i2c_data
|
input wire DIR,
|
||||||
|
input wire [15:0] i2c_data_write,
|
||||||
|
input wire transact_width, /* 0=byte 1=word */
|
||||||
|
input wire ignore_ack,
|
||||||
|
output reg [15:0] i2c_data_read=16'h4141
|
||||||
);
|
);
|
||||||
|
|
||||||
|
//assign i2c_data_read=16'h0042;
|
||||||
|
|
||||||
|
reg DIR_latched;
|
||||||
|
|
||||||
reg SDA;
|
reg SDA;
|
||||||
|
|
||||||
assign SDA_output=SDA;
|
assign SDA_output=SDA;
|
||||||
@ -37,9 +45,11 @@ assign SDA_output=SDA;
|
|||||||
reg [5:0] i2c_state = 6'b100100;
|
reg [5:0] i2c_state = 6'b100100;
|
||||||
|
|
||||||
reg [3:0] data_bit_counter;
|
reg [3:0] data_bit_counter;
|
||||||
reg [7:0] data_internal;
|
reg [15:0] data_internal;
|
||||||
reg [6:0]address_internal;
|
reg [6:0]address_internal;
|
||||||
|
|
||||||
|
reg trans_width_latch;
|
||||||
|
|
||||||
always @(posedge clock) begin
|
always @(posedge clock) begin
|
||||||
case (i2c_state)
|
case (i2c_state)
|
||||||
/***** start sequence ******/
|
/***** start sequence ******/
|
||||||
@ -90,7 +100,7 @@ always @(posedge clock) begin
|
|||||||
end
|
end
|
||||||
6'b001000:begin
|
6'b001000:begin
|
||||||
SCL<=0;
|
SCL<=0;
|
||||||
SDA<=0;/*Write=0 Read=1*/
|
SDA<=DIR_latched;/*Write=0 Read=1*/
|
||||||
i2c_state<=6'b001001;
|
i2c_state<=6'b001001;
|
||||||
end
|
end
|
||||||
6'b001001:begin
|
6'b001001:begin
|
||||||
@ -151,28 +161,40 @@ always @(posedge clock) begin
|
|||||||
end
|
end
|
||||||
/****** Send data ********/
|
/****** Send data ********/
|
||||||
6'b010100:begin
|
6'b010100:begin
|
||||||
SCL<=0;
|
if(DIR_latched==1'b1)begin
|
||||||
|
SDA_direction<=0;
|
||||||
|
end else begin
|
||||||
SDA_direction<=1;
|
SDA_direction<=1;
|
||||||
|
end
|
||||||
|
SCL<=0;
|
||||||
i2c_state<=6'b010101;
|
i2c_state<=6'b010101;
|
||||||
end
|
end
|
||||||
6'b010101:begin
|
6'b010101:begin
|
||||||
SCL<=0;
|
SCL<=0;
|
||||||
|
if(DIR_latched==1'b0)begin
|
||||||
SDA<=data_internal[7:7];
|
SDA<=data_internal[7:7];
|
||||||
data_internal[7:0]<={data_internal[6:0],1'b0};
|
data_internal[7:0]<={data_internal[6:0],1'b0};
|
||||||
|
end
|
||||||
data_bit_counter<=data_bit_counter+1;
|
data_bit_counter<=data_bit_counter+1;
|
||||||
i2c_state<=6'b010110;
|
i2c_state<=6'b010110;
|
||||||
end
|
end
|
||||||
6'b010110:begin
|
6'b010110:begin
|
||||||
SCL<=1;
|
SCL<=1;
|
||||||
|
if(DIR_latched==1'b1)begin
|
||||||
|
//i2c_data_read[15:0]<={8'h0,SDA_input,i2c_data_read[7:1]};
|
||||||
|
|
||||||
|
i2c_data_read[15:0]<={8'h0,i2c_data_read[6:0],SDA_input};
|
||||||
|
end
|
||||||
i2c_state<=6'b010111;
|
i2c_state<=6'b010111;
|
||||||
end
|
end
|
||||||
6'b010111:begin
|
6'b010111:begin
|
||||||
SCL<=1;
|
SCL<=1;
|
||||||
if(data_bit_counter==4'd8)begin
|
if(data_bit_counter==4'd8)begin
|
||||||
i2c_state<=6'b011000;
|
i2c_state<=6'b011000;
|
||||||
end else
|
end else begin
|
||||||
i2c_state<=6'b010100;
|
i2c_state<=6'b010100;
|
||||||
end
|
end
|
||||||
|
end
|
||||||
/****** Acknowledge ********/
|
/****** Acknowledge ********/
|
||||||
6'b011000:begin
|
6'b011000:begin
|
||||||
SDA_direction<=0;
|
SDA_direction<=0;
|
||||||
@ -189,11 +211,62 @@ always @(posedge clock) begin
|
|||||||
end
|
end
|
||||||
6'b011011:begin
|
6'b011011:begin
|
||||||
SCL<=1;
|
SCL<=1;
|
||||||
if (SDA_input==1)begin
|
if (SDA_input==0||ignore_ack==1'b1)begin
|
||||||
i2c_state<=6'b111111;
|
if(trans_width_latch==1'b1)begin
|
||||||
end else begin
|
i2c_state<=6'b100101;
|
||||||
|
data_bit_counter<=4'd0;
|
||||||
|
end else
|
||||||
i2c_state<=6'b011100;
|
i2c_state<=6'b011100;
|
||||||
SDA_direction<=1;
|
SDA_direction<=1;
|
||||||
|
end else begin
|
||||||
|
i2c_state<=6'b111111;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
/****** Send data (16bit) ********/
|
||||||
|
6'b100101:begin
|
||||||
|
SCL<=0;
|
||||||
|
SDA_direction<=1;
|
||||||
|
i2c_state<=6'b100110;
|
||||||
|
end
|
||||||
|
6'b100110:begin
|
||||||
|
SCL<=0;
|
||||||
|
SDA<=data_internal[15:15];
|
||||||
|
data_internal[15:8]<={data_internal[14:8],1'b0};
|
||||||
|
data_bit_counter<=data_bit_counter+1;
|
||||||
|
i2c_state<=6'b100111;
|
||||||
|
end
|
||||||
|
6'b100111:begin
|
||||||
|
SCL<=1;
|
||||||
|
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==0||ignore_ack==1'b1)begin
|
||||||
|
i2c_state<=6'b011100;
|
||||||
|
SDA_direction<=1;
|
||||||
|
end else begin
|
||||||
|
i2c_state<=6'b111111;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
/****** separator ********/
|
/****** separator ********/
|
||||||
@ -239,11 +312,13 @@ always @(posedge clock) begin
|
|||||||
I2C_BUSY<=0;
|
I2C_BUSY<=0;
|
||||||
end
|
end
|
||||||
6'b100100:begin
|
6'b100100:begin
|
||||||
if(I2C_SEND==1)begin
|
if(I2C_TRANSACT==1)begin
|
||||||
I2C_BUSY<=1;
|
I2C_BUSY<=1;
|
||||||
i2c_state<=0;
|
i2c_state<=0;
|
||||||
data_internal<=i2c_data;
|
data_internal<=i2c_data_write;
|
||||||
address_internal<=address;
|
address_internal<=address;
|
||||||
|
trans_width_latch<=transact_width;
|
||||||
|
DIR_latched<=DIR;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
default:begin
|
default:begin
|
||||||
|
118
system/peripherals/I2C_driver_multiplexer.v
Normal file
118
system/peripherals/I2C_driver_multiplexer.v
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
/* 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,
|
||||||
|
|
||||||
|
////// 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 ///////
|
||||||
|
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
|
||||||
|
);
|
||||||
|
|
||||||
|
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;
|
||||||
|
end else begin
|
||||||
|
IN2_I2C_DATA_READ<=OUT_I2C_DATA_READ;
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
@ -32,9 +32,10 @@ input new_backlight,
|
|||||||
input backlight_update,
|
input backlight_update,
|
||||||
|
|
||||||
input I2C_BUSY,
|
input I2C_BUSY,
|
||||||
output reg I2C_SEND=0,
|
output reg I2C_TRANSACT=0,
|
||||||
|
output reg DIR=0,
|
||||||
|
|
||||||
output reg [7:0]i2c_data
|
output reg [7:0]i2c_data_write
|
||||||
);
|
);
|
||||||
|
|
||||||
reg backlight=1;
|
reg backlight=1;
|
||||||
@ -49,52 +50,52 @@ always @(posedge clock) begin
|
|||||||
4'b0000: begin /*Idle*/
|
4'b0000: begin /*Idle*/
|
||||||
if(pcf_write_req&&I2C_BUSY==0)begin
|
if(pcf_write_req&&I2C_BUSY==0)begin
|
||||||
pcf_state<=4'b0001;
|
pcf_state<=4'b0001;
|
||||||
I2C_SEND<=0;
|
I2C_TRANSACT<=0;
|
||||||
pcf_busy<=1;
|
pcf_busy<=1;
|
||||||
end else if(backlight_latch&&I2C_BUSY==0)begin
|
end else if(backlight_latch&&I2C_BUSY==0)begin
|
||||||
pcf_state<=4'b1111;
|
pcf_state<=4'b1111;
|
||||||
I2C_SEND<=0;
|
I2C_TRANSACT<=0;
|
||||||
pcf_busy<=1;
|
pcf_busy<=1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0001: begin
|
4'b0001: begin
|
||||||
if(I2C_BUSY==0)begin
|
if(I2C_BUSY==0)begin
|
||||||
i2c_data<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||||
I2C_SEND<=1;
|
I2C_TRANSACT<=1;
|
||||||
backlight_latch<=0;
|
backlight_latch<=0;
|
||||||
pcf_state<=4'b0010;
|
pcf_state<=4'b0010;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0010:begin
|
4'b0010:begin
|
||||||
if(I2C_BUSY==1)begin
|
if(I2C_BUSY==1)begin
|
||||||
I2C_SEND<=0;
|
I2C_TRANSACT<=0;
|
||||||
pcf_state<=4'b0011;
|
pcf_state<=4'b0011;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0011: begin
|
4'b0011: begin
|
||||||
if(I2C_BUSY==0)begin
|
if(I2C_BUSY==0)begin
|
||||||
i2c_data<={pcf_data[3:0],backlight,1'b1,1'b0,pcf_command_data};
|
i2c_data_write<={pcf_data[3:0],backlight,1'b1,1'b0,pcf_command_data};
|
||||||
I2C_SEND<=1;
|
I2C_TRANSACT<=1;
|
||||||
backlight_latch<=0;
|
backlight_latch<=0;
|
||||||
pcf_state<=4'b0100;
|
pcf_state<=4'b0100;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0100:begin
|
4'b0100:begin
|
||||||
if(I2C_BUSY==1)begin
|
if(I2C_BUSY==1)begin
|
||||||
I2C_SEND<=0;
|
I2C_TRANSACT<=0;
|
||||||
pcf_state<=4'b0101;
|
pcf_state<=4'b0101;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0101: begin
|
4'b0101: begin
|
||||||
if(I2C_BUSY==0)begin
|
if(I2C_BUSY==0)begin
|
||||||
i2c_data<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||||
I2C_SEND<=1;
|
I2C_TRANSACT<=1;
|
||||||
pcf_state<=4'b0110;
|
pcf_state<=4'b0110;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
4'b0110: begin
|
4'b0110: begin
|
||||||
if(I2C_BUSY==1)begin
|
if(I2C_BUSY==1)begin
|
||||||
I2C_SEND<=0;
|
I2C_TRANSACT<=0;
|
||||||
pcf_state<=4'b0111;
|
pcf_state<=4'b0111;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -107,12 +108,12 @@ always @(posedge clock) begin
|
|||||||
4'b1111:begin
|
4'b1111:begin
|
||||||
if(I2C_BUSY==1)begin
|
if(I2C_BUSY==1)begin
|
||||||
pcf_state<=4'b0000;
|
pcf_state<=4'b0000;
|
||||||
I2C_SEND<=1'b0;
|
I2C_TRANSACT<=1'b0;
|
||||||
pcf_busy<=1'b0;
|
pcf_busy<=1'b0;
|
||||||
end else begin
|
end else begin
|
||||||
i2c_data<={4'b0,backlight,1'b0,1'b0,1'b0};
|
i2c_data_write<={4'b0,backlight,1'b0,1'b0,1'b0};
|
||||||
backlight_latch<=0;
|
backlight_latch<=0;
|
||||||
I2C_SEND<=1'b1;
|
I2C_TRANSACT<=1'b1;
|
||||||
pcf_busy<=1'b1;
|
pcf_busy<=1'b1;
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user