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
|
||||
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 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=.
|
||||
|
||||
NO_ASM=1
|
||||
@ -55,11 +55,16 @@ mrproper: clean
|
||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=boot_code/ -C boot_code mrproper
|
||||
|
||||
.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
|
||||
|
||||
.PHONY: upload_bootrom
|
||||
upload_bootrom: boot_code/brainfuck_mandelbrot.bin
|
||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system upload_bootrom
|
||||
|
||||
|
||||
.PHONY: fpga_sim
|
||||
fpga_sim: boot_code/bios.stxt
|
||||
fpga_sim: boot_code/i2c_bootloader.stxt
|
||||
${Q}make ${MAKEOPTS} PRINT_PATH_PREFIX=system/ -C system fpga_sim
|
||||
|
||||
.PHONY: help
|
||||
@ -76,6 +81,8 @@ help:
|
||||
@echo 'Synthesis targets:'
|
||||
@echo ' upload_bitstream - Build a bitstream for the board selected in'
|
||||
@echo ' common.mk and upload it if possible'
|
||||
@echo ' upload_bootrom - Build the rom file and upload it to an I2C rom'
|
||||
@echo ' Currently only the MiniPro programmer is supported'
|
||||
@echo ' fpga_sim - Simulate the SoC that gets build for the configured'
|
||||
@echo ' fpga board'
|
||||
@echo ''
|
||||
|
@ -18,7 +18,7 @@
|
||||
|
||||
PRINT_PATH_PREFIX=./
|
||||
SOURCE_FULL=brainfuck_interpreted.asm brainfuck_compiled.asm brainfuck_mandelbrot.asm pipeline_ideal.asm fibonacci.asm gnome_sort.asm cache_fill_and_empty.asm colored_led.asm
|
||||
SOURCE_SHORT=bios.asm
|
||||
SOURCE_SHORT=bios.asm i2c_bootloader.asm
|
||||
BINARIES=$(subst .asm,.txt,${SOURCE_FULL}) $(subst .asm,.stxt,${SOURCE_SHORT})
|
||||
BUILD_FILES=${BINARIES}
|
||||
BUILD_FILES+=$(subst .asm,.memdump,${SOURCE_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
|
||||
colored_led.bin: dos_layer.asm
|
||||
bios.bin: LiteDram_init.asm brainfuck_compiler_v1.asm hello_9086.bf.asm dos_layer.asm
|
||||
i2c_bootloader.bin: LiteDram_init.asm
|
||||
|
||||
fibonacci.bin: helpers.asm
|
||||
gnome_sort.bin: helpers.asm
|
||||
|
@ -3,7 +3,7 @@
|
||||
org 0x100
|
||||
output_program:
|
||||
|
||||
org 0xD000
|
||||
org 0xC000
|
||||
mov sp,#SMALL_STACK
|
||||
call INIT_INT_VECT_TABLE
|
||||
INCLUDE brainfuck_compiler_v1.asm
|
||||
@ -15,7 +15,7 @@ INCLUDE mandelbrot.bf.asm
|
||||
|
||||
|
||||
.ORG 0xFFF0
|
||||
MOV AX,#0xD000
|
||||
MOV AX,#0xC000
|
||||
JMP AX
|
||||
|
||||
.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_DFU_SUFFIX = @echo ' DFU-SUFFIX '${PRINT_PATH_PREFIX}$@;
|
||||
QUIET_DFU_UTIL = @echo ' DFU-UTIL '${PRINT_PATH_PREFIX}$<;
|
||||
QUIET_MINIPRO = @echo ' MINIPRO '${PRINT_PATH_PREFIX}${ROM_FILE};
|
||||
|
||||
QUIET_DOWNLOAD = @echo ' DOWNLOAD '${PRINT_PATH_PREFIX}$@;
|
||||
|
||||
|
@ -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}
|
||||
|
||||
.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,$^),$<)
|
||||
${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 ####
|
||||
@ -157,6 +157,9 @@ dfu_upload:${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.dfu
|
||||
${QUIET_DFU_UTIL}
|
||||
${Q}stdbuf -o0 dfu-util --download "$<" |stdbuf -o0 tr '\n' '\a' | stdbuf -o0 tr '\r' '\n' | grep Download --line-buffered | stdbuf -o0 tr '\n' '\r' |stdbuf -o0 tr '\a' '\n'
|
||||
|
||||
minipro_upload:
|
||||
${QUIET_MINIPRO}
|
||||
${Q}minipro -p ${ROM_PART_ID} -w ${ROM_FILE}
|
||||
|
||||
################################################################################
|
||||
#### CLEAN-UP ####
|
||||
|
@ -15,18 +15,22 @@ FPGA_FILE_EXT=dfu
|
||||
# 6 is the slowest and 8 is the fastest
|
||||
ECP5_SPEED_GRADE=8
|
||||
|
||||
ROM_PART_ID=24lc512
|
||||
|
||||
######## End of user configuration ########
|
||||
|
||||
#NOT USED OUTSIDE OF HERE
|
||||
FPGA_SOC_COMMON_SOURCES=peripherals/I2C_driver.v peripherals/ascii_to_HD44780_driver.v peripherals/pcf8574_for_HD44780.v peripherals/Wishbone_IO_driver.v peripherals/Wishbone_memory_driver.v
|
||||
FPGA_SOC_COMMON_SOURCES=peripherals/I2C_driver.v peripherals/ascii_to_HD44780_driver.v peripherals/pcf8574_for_HD44780.v peripherals/Wishbone_IO_driver.v peripherals/Wishbone_memory_driver.v peripherals/I2C_driver_multiplexer.v peripherals/CPU_to_I2C_driver_bridge.v
|
||||
|
||||
FPGA_SOC_SOURCES=${FPGA_SOC_COMMON_SOURCES} external_ip/litedram_core_ecp5_phy.v
|
||||
FPGA_SOC_SIM_SOURCES=${FPGA_SOC_COMMON_SOURCES} fpga_config/OrangeCrab_r0.2.1/verilator_config.vlt external_ip/litedram_core_ecp5_phy_sim.v
|
||||
|
||||
FPGA_BOOTCODE=../boot_code/bios.stxt
|
||||
FPGA_BOOTCODE=../boot_code/i2c_bootloader.stxt
|
||||
|
||||
ROM_FILE=../boot_code/brainfuck_mandelbrot.bin
|
||||
|
||||
upload_bitstream: dfu_upload
|
||||
upload_bootrom: minipro_upload
|
||||
|
||||
${BUILD_FILES_PREFIX}bitstream_${BUILD_NAME}.bit:${BUILD_FILES_PREFIX}nextpnr-ecp5_${BUILD_NAME}.bit
|
||||
${Q}cp "$^" "$@"
|
||||
|
@ -193,16 +193,16 @@ end
|
||||
// Cache to allow the slow display to have a
|
||||
// chance to keep up with the relentless CPU
|
||||
|
||||
reg [6:0] disp_cache_start=0;
|
||||
reg [6:0] disp_cache_end=0;
|
||||
reg [7:0] disp_write_cache [127:0];
|
||||
reg [7:0] disp_cache_start=0;
|
||||
reg [7:0] disp_cache_end=0;
|
||||
reg [7:0] disp_write_cache [255:0];
|
||||
reg ascii_state=0;
|
||||
always @(posedge CPU_SPEED)begin
|
||||
|
||||
if(wr==0)begin
|
||||
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
|
||||
disp_write_cache[disp_cache_end]<=data_bus_write[15:8];
|
||||
disp_cache_end<=disp_cache_end+7'd1;
|
||||
disp_cache_end<=disp_cache_end+8'd1;
|
||||
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
|
||||
if(data_bus_write[0:0]==1)
|
||||
rgb_led_color<=3'b000;
|
||||
@ -215,7 +215,7 @@ always @(posedge CPU_SPEED)begin
|
||||
$write("%s" ,disp_write_cache[disp_cache_start]); // TODO: maybe simulate the i2c lcd
|
||||
`endif
|
||||
ascii_data<=disp_write_cache[disp_cache_start];
|
||||
disp_cache_start<=disp_cache_start+7'd1;
|
||||
disp_cache_start<=disp_cache_start+8'd1;
|
||||
ascii_data_write_req<=1;
|
||||
ascii_state<=1'b1;
|
||||
end
|
||||
@ -245,7 +245,7 @@ doublemem #( .RAM_SIZE_IN_BYTES(2048) ) boot_rom
|
||||
/// 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;
|
||||
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));
|
||||
@ -264,7 +264,17 @@ wire DDR3_ram_cs = (IOMEM==0)&&(address_bus[15:12]!=4'hF);
|
||||
// 0x3F | WISHBONE |
|
||||
//
|
||||
assign wishbone_cs=!((IOMEM==1)&&(address_bus[7:4] == 4'h4));
|
||||
assign i2c_cs= !((IOMEM==1)&&(address_bus[7:4] == 4'h6));
|
||||
|
||||
assign wait_state_I2C=(i2c_cs==1'b0&&rd==1'b0)^i2c_cs_1d;
|
||||
|
||||
reg i2c_cs_1d;
|
||||
|
||||
always @(posedge CPU_SPEED)begin
|
||||
i2c_cs_1d<=(i2c_cs==1'b0&&rd==1'b0);
|
||||
end // TODO: Probably would need to so the same for the wishbone IO
|
||||
|
||||
wire wait_state_I2C;
|
||||
/// DDR3 Controller
|
||||
|
||||
wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked;
|
||||
@ -323,7 +333,7 @@ Wishbone_memory_driver Wishbone_memory_driver(
|
||||
.BHE(BHE),
|
||||
.data_bus_in(data_bus_write),
|
||||
.data_bus_out(data_bus_read_DDR3),
|
||||
.wait_state(wait_state),
|
||||
.wait_state(wait_state_WBIO),
|
||||
.read_n(rd),
|
||||
.write_n(wr),
|
||||
.chip_select_n(!(DDR3_ram_cs&&ddr3_init_done)),
|
||||
@ -341,6 +351,8 @@ Wishbone_memory_driver Wishbone_memory_driver(
|
||||
);
|
||||
|
||||
wire wait_state;
|
||||
assign wait_state=wait_state_WBIO||wait_state_I2C;
|
||||
wire wait_state_WBIO;
|
||||
|
||||
wire wb_ctrl_ack;
|
||||
wire [29:0] wb_ctrl_adr;
|
||||
@ -422,6 +434,38 @@ litedram_core DDR3_RAM_DRIVER(
|
||||
.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
|
||||
|
||||
wire ascii_data_ready;
|
||||
@ -448,7 +492,14 @@ ascii_to_HD44780_driver LCD_DRIVER(
|
||||
|
||||
wire pcf_write_req,pcf_command_data,pcf_busy;
|
||||
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(
|
||||
.clock(I2C_SPEED),
|
||||
@ -461,16 +512,61 @@ pcf8574_for_HD44780 PCF8574_driver(
|
||||
.new_backlight(1'b0),
|
||||
.backlight_update(1'b0),
|
||||
|
||||
.I2C_BUSY(I2C_BUSY),
|
||||
.I2C_SEND(I2C_SEND),
|
||||
.DIR(DISP_DIR),
|
||||
.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
|
||||
|
||||
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(
|
||||
.clock(I2C_SPEED),
|
||||
@ -480,10 +576,15 @@ I2C_driver i2c_driver(
|
||||
.SDA_direction(SDA_direction),
|
||||
.SCL(SCL),
|
||||
|
||||
.address(7'h27),
|
||||
.I2C_BUSY(I2C_BUSY),
|
||||
.I2C_SEND(I2C_SEND),
|
||||
.i2c_data(i2c_data)
|
||||
.address(MULT_TO_DRIV_I2C_ADDRESS),
|
||||
.I2C_BUSY(MULT_TO_DRIV_I2C_BUSY),
|
||||
.I2C_TRANSACT(MULT_TO_DRIV_I2C_TRANSACT),
|
||||
.DIR(MULT_TO_DRIV_DIR),
|
||||
.i2c_data_write(MULT_TO_DRIV_DATA_WRITE),
|
||||
.i2c_data_read(MULT_TO_DRIV_DATA_READ),
|
||||
|
||||
.transact_width(MULT_TO_DRIV_TRANS_WIDTH),
|
||||
.ignore_ack(MULT_TO_DRIV_IGN_ACK)
|
||||
);
|
||||
|
||||
`ifdef SYNTHESIS
|
||||
|
@ -48,7 +48,7 @@ initial begin
|
||||
$readmemh(boot_code, memory,0,(RAM_SIZE_IN_BYTES/2)-1);
|
||||
`else
|
||||
//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
|
||||
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,
|
||||
output reg I2C_BUSY=0,
|
||||
input wire I2C_SEND,
|
||||
input wire [7:0] i2c_data
|
||||
input wire I2C_TRANSACT,
|
||||
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;
|
||||
|
||||
assign SDA_output=SDA;
|
||||
@ -37,9 +45,11 @@ assign SDA_output=SDA;
|
||||
reg [5:0] i2c_state = 6'b100100;
|
||||
|
||||
reg [3:0] data_bit_counter;
|
||||
reg [7:0] data_internal;
|
||||
reg [15:0] data_internal;
|
||||
reg [6:0]address_internal;
|
||||
|
||||
reg trans_width_latch;
|
||||
|
||||
always @(posedge clock) begin
|
||||
case (i2c_state)
|
||||
/***** start sequence ******/
|
||||
@ -90,7 +100,7 @@ always @(posedge clock) begin
|
||||
end
|
||||
6'b001000:begin
|
||||
SCL<=0;
|
||||
SDA<=0;/*Write=0 Read=1*/
|
||||
SDA<=DIR_latched;/*Write=0 Read=1*/
|
||||
i2c_state<=6'b001001;
|
||||
end
|
||||
6'b001001:begin
|
||||
@ -151,28 +161,40 @@ always @(posedge clock) begin
|
||||
end
|
||||
/****** Send data ********/
|
||||
6'b010100:begin
|
||||
SCL<=0;
|
||||
if(DIR_latched==1'b1)begin
|
||||
SDA_direction<=0;
|
||||
end else begin
|
||||
SDA_direction<=1;
|
||||
end
|
||||
SCL<=0;
|
||||
i2c_state<=6'b010101;
|
||||
end
|
||||
6'b010101:begin
|
||||
SCL<=0;
|
||||
if(DIR_latched==1'b0)begin
|
||||
SDA<=data_internal[7:7];
|
||||
data_internal[7:0]<={data_internal[6:0],1'b0};
|
||||
end
|
||||
data_bit_counter<=data_bit_counter+1;
|
||||
i2c_state<=6'b010110;
|
||||
end
|
||||
6'b010110:begin
|
||||
SCL<=1;
|
||||
if(DIR_latched==1'b1)begin
|
||||
//i2c_data_read[15:0]<={8'h0,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;
|
||||
end
|
||||
6'b010111:begin
|
||||
SCL<=1;
|
||||
if(data_bit_counter==4'd8)begin
|
||||
i2c_state<=6'b011000;
|
||||
end else
|
||||
end else begin
|
||||
i2c_state<=6'b010100;
|
||||
end
|
||||
end
|
||||
/****** Acknowledge ********/
|
||||
6'b011000:begin
|
||||
SDA_direction<=0;
|
||||
@ -189,11 +211,62 @@ always @(posedge clock) begin
|
||||
end
|
||||
6'b011011:begin
|
||||
SCL<=1;
|
||||
if (SDA_input==1)begin
|
||||
i2c_state<=6'b111111;
|
||||
end else begin
|
||||
if (SDA_input==0||ignore_ack==1'b1)begin
|
||||
if(trans_width_latch==1'b1)begin
|
||||
i2c_state<=6'b100101;
|
||||
data_bit_counter<=4'd0;
|
||||
end else
|
||||
i2c_state<=6'b011100;
|
||||
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
|
||||
/****** separator ********/
|
||||
@ -239,11 +312,13 @@ always @(posedge clock) begin
|
||||
I2C_BUSY<=0;
|
||||
end
|
||||
6'b100100:begin
|
||||
if(I2C_SEND==1)begin
|
||||
if(I2C_TRANSACT==1)begin
|
||||
I2C_BUSY<=1;
|
||||
i2c_state<=0;
|
||||
data_internal<=i2c_data;
|
||||
data_internal<=i2c_data_write;
|
||||
address_internal<=address;
|
||||
trans_width_latch<=transact_width;
|
||||
DIR_latched<=DIR;
|
||||
end
|
||||
end
|
||||
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 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;
|
||||
@ -49,52 +50,52 @@ always @(posedge clock) begin
|
||||
4'b0000: begin /*Idle*/
|
||||
if(pcf_write_req&&I2C_BUSY==0)begin
|
||||
pcf_state<=4'b0001;
|
||||
I2C_SEND<=0;
|
||||
I2C_TRANSACT<=0;
|
||||
pcf_busy<=1;
|
||||
end else if(backlight_latch&&I2C_BUSY==0)begin
|
||||
pcf_state<=4'b1111;
|
||||
I2C_SEND<=0;
|
||||
I2C_TRANSACT<=0;
|
||||
pcf_busy<=1;
|
||||
end
|
||||
end
|
||||
4'b0001: begin
|
||||
if(I2C_BUSY==0)begin
|
||||
i2c_data<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||
I2C_SEND<=1;
|
||||
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||
I2C_TRANSACT<=1;
|
||||
backlight_latch<=0;
|
||||
pcf_state<=4'b0010;
|
||||
end
|
||||
end
|
||||
4'b0010:begin
|
||||
if(I2C_BUSY==1)begin
|
||||
I2C_SEND<=0;
|
||||
I2C_TRANSACT<=0;
|
||||
pcf_state<=4'b0011;
|
||||
end
|
||||
end
|
||||
4'b0011: begin
|
||||
if(I2C_BUSY==0)begin
|
||||
i2c_data<={pcf_data[3:0],backlight,1'b1,1'b0,pcf_command_data};
|
||||
I2C_SEND<=1;
|
||||
i2c_data_write<={pcf_data[3:0],backlight,1'b1,1'b0,pcf_command_data};
|
||||
I2C_TRANSACT<=1;
|
||||
backlight_latch<=0;
|
||||
pcf_state<=4'b0100;
|
||||
end
|
||||
end
|
||||
4'b0100:begin
|
||||
if(I2C_BUSY==1)begin
|
||||
I2C_SEND<=0;
|
||||
I2C_TRANSACT<=0;
|
||||
pcf_state<=4'b0101;
|
||||
end
|
||||
end
|
||||
4'b0101: begin
|
||||
if(I2C_BUSY==0)begin
|
||||
i2c_data<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||
I2C_SEND<=1;
|
||||
i2c_data_write<={pcf_data[3:0],backlight,1'b0,1'b0,pcf_command_data};
|
||||
I2C_TRANSACT<=1;
|
||||
pcf_state<=4'b0110;
|
||||
end
|
||||
end
|
||||
4'b0110: begin
|
||||
if(I2C_BUSY==1)begin
|
||||
I2C_SEND<=0;
|
||||
I2C_TRANSACT<=0;
|
||||
pcf_state<=4'b0111;
|
||||
end
|
||||
end
|
||||
@ -107,12 +108,12 @@ always @(posedge clock) begin
|
||||
4'b1111:begin
|
||||
if(I2C_BUSY==1)begin
|
||||
pcf_state<=4'b0000;
|
||||
I2C_SEND<=1'b0;
|
||||
I2C_TRANSACT<=1'b0;
|
||||
pcf_busy<=1'b0;
|
||||
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;
|
||||
I2C_SEND<=1'b1;
|
||||
I2C_TRANSACT<=1'b1;
|
||||
pcf_busy<=1'b1;
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user