(Tim) Efthimis Kritikos
1966ab78b4
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.
619 lines
15 KiB
Verilog
619 lines
15 KiB
Verilog
/* top.v - Implements FPGA and Board specific circuitry
|
|
|
|
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/>. */
|
|
|
|
`include "error_header.v"
|
|
`ifdef OUTPUT_JSON_STATISTICS
|
|
`include "config.v"
|
|
`endif
|
|
|
|
module fpga_top(
|
|
input clk48,
|
|
input user_button,
|
|
// output reset_n,
|
|
|
|
output rgb_led0_r,
|
|
output rgb_led0_g,
|
|
output rgb_led0_b,
|
|
|
|
`ifdef SYNTHESIS
|
|
output wire [15:0] ddram_a, // [15:13] are unused in litex as well, they just also route them through a trellis block
|
|
output wire [2:0] ddram_ba,
|
|
output wire ddram_cas_n,
|
|
output wire ddram_cke,
|
|
output wire ddram_clk_p,
|
|
output wire ddram_cs_n,
|
|
output wire [1:0] ddram_dm,
|
|
input wire [15:0] ddram_dq,
|
|
input wire [1:0] ddram_dqs_p,
|
|
output wire [1:0] ddram_gnd,
|
|
output wire ddram_odt,
|
|
output wire ddram_ras_n,
|
|
output wire ddram_reset_n,
|
|
output wire [5:0] ddram_vccio,
|
|
output wire ddram_we_n,
|
|
|
|
inout i2c_sda,/*sda*/
|
|
output i2c_scl /*scl*/
|
|
`else
|
|
output i2c_dir,
|
|
output i2c_scl,
|
|
input i2c_sda_in,
|
|
output i2c_sda_out
|
|
`endif
|
|
);
|
|
|
|
`ifndef SYNTHESIS
|
|
string waveform_name;
|
|
initial begin
|
|
if($value$plusargs("WAVEFORM=%s",waveform_name))begin
|
|
$dumpfile(waveform_name);
|
|
$dumpvars(0,p,cycles);
|
|
end
|
|
end
|
|
//TODO: should there be some common file between all the fpga_tops and system.v for this stuff?
|
|
always @(posedge clk48) begin
|
|
if(HALT==1&&disp_cache_start==disp_cache_end)begin
|
|
$finish;
|
|
end
|
|
end
|
|
reg sane;
|
|
always @(posedge reset)begin sane<=1; end
|
|
always @( ERROR ) begin
|
|
if ( ERROR != `ERR_NO_ERROR && sane == 1 ) begin
|
|
$display("PROCESSOR RUN INTO AN ERROR.");
|
|
case (ERROR)
|
|
default:begin
|
|
end
|
|
`ERR_UNIMPL_INSTRUCTION:begin
|
|
$display("Unimplemented instruction");
|
|
end
|
|
`ERR_UNIMPL_ADDRESSING_MODE: begin
|
|
$display("Unimplemented addressing mode");
|
|
end
|
|
endcase
|
|
$finish;
|
|
end
|
|
end
|
|
`endif
|
|
|
|
`ifdef SYNTHESIS
|
|
assign ddram_a[15:13] = 3'b0;
|
|
assign ddram_vccio = 6'd63;
|
|
assign ddram_gnd = 2'd0;
|
|
`endif
|
|
|
|
wire HALT;
|
|
wire [`ERROR_BITS-1:0]ERROR;
|
|
wire [19:0] address_bus;
|
|
wire [15:0] data_bus_read,data_bus_write;
|
|
wire rd,wr,BHE,IOMEM;
|
|
|
|
|
|
wire CPU_SPEED;
|
|
|
|
processor p(
|
|
.clock(CPU_SPEED),
|
|
.reset(reset),
|
|
.HALT(HALT),
|
|
.ERROR(ERROR),
|
|
.external_address_bus(address_bus),
|
|
.external_data_bus_read(data_bus_read),
|
|
.external_data_bus_write(data_bus_write),
|
|
.wait_state(wait_state),
|
|
.read(rd),
|
|
.write(wr),
|
|
.BHE(BHE),
|
|
.IOMEM(IOMEM)
|
|
`ifdef CALCULATE_IPC
|
|
/* STATISTICS */ ,.new_instruction(new_instruction)
|
|
`endif
|
|
`ifdef OUTPUT_JSON_STATISTICS
|
|
/* */ ,.L1_SIZE_STAT(L1_SIZE_STAT), .VALID_INSTRUCTION_STAT(VALID_INSTRUCTION_STAT), .jump_req_debug(jump_req_debug)
|
|
`endif
|
|
);
|
|
|
|
/* verilator lint_off UNUSEDSIGNAL */
|
|
`ifdef CALCULATE_IPC
|
|
wire new_instruction;
|
|
`endif
|
|
`ifdef OUTPUT_JSON_STATISTICS
|
|
wire [`L1_CACHE_SIZE-1:0]L1_SIZE_STAT;
|
|
wire VALID_INSTRUCTION_STAT;
|
|
wire jump_req_debug;
|
|
`endif
|
|
/* verilator lint_on UNUSEDSIGNAL */
|
|
|
|
|
|
reg [2:0]rgb_led_color;
|
|
assign rgb_led0_r=rgb_led_color[0];
|
|
assign rgb_led0_g=rgb_led_color[1];
|
|
assign rgb_led0_b=rgb_led_color[2];
|
|
|
|
// A bit useless since if the cpu ERRORS out or HALTS it will continue executing anyway
|
|
//always @(HALT or ERROR or user_button) begin
|
|
// if (HALT==1) begin
|
|
// /* yellow */
|
|
// rgb_led_color<=3'b100;
|
|
// end else if (ERROR != `ERROR_BITS'b0) begin
|
|
// /* red */
|
|
// rgb_led_color<=3'b110;
|
|
// end else begin
|
|
// /* green */
|
|
// rgb_led_color<=3'b101;
|
|
// end
|
|
//end
|
|
|
|
// Create a 27 bit register
|
|
reg [26:0] counter = 0;
|
|
|
|
// Every positive edge increment register by 1
|
|
always @(posedge clk48) begin
|
|
counter <= counter + 1;
|
|
end
|
|
|
|
/*** RESET CIRCUIT ***/
|
|
|
|
reg reset=0;
|
|
reg [1:0] state=0;
|
|
|
|
always @(posedge counter[15]) begin
|
|
if(user_button==0)
|
|
state<=2'b00;
|
|
case (state)
|
|
2'b00:begin
|
|
reset<=0;
|
|
state<=2'b01;
|
|
end
|
|
2'b01:begin
|
|
reset<=1;
|
|
state<=2'b10;
|
|
end
|
|
default: begin
|
|
end
|
|
endcase
|
|
end
|
|
|
|
//------------------------------------------//
|
|
// Cache to allow the slow display to have a
|
|
// chance to keep up with the relentless CPU
|
|
|
|
reg [7:0] disp_cache_start=0;
|
|
reg [7:0] disp_cache_end=0;
|
|
reg [7:0] disp_write_cache [255:0];
|
|
reg ascii_state=0;
|
|
always @(posedge CPU_SPEED)begin
|
|
|
|
if(wr==0)begin
|
|
if(IOMEM==1'b1 && address_bus[7:0]==8'hA5 )begin
|
|
disp_write_cache[disp_cache_end]<=data_bus_write[15:8];
|
|
disp_cache_end<=disp_cache_end+8'd1;
|
|
end else if(IOMEM==1'b1 && address_bus[7:0]==8'hB0 )begin
|
|
if(data_bus_write[0:0]==1)
|
|
rgb_led_color<=3'b000;
|
|
else
|
|
rgb_led_color<=3'b111;
|
|
end
|
|
end else if(ascii_state==1'b0)begin
|
|
if(ascii_data_ready&disp_cache_start!=disp_cache_end)begin
|
|
`ifndef SYNTHESIS
|
|
$write("%s" ,disp_write_cache[disp_cache_start]); // TODO: maybe simulate the i2c lcd
|
|
`endif
|
|
ascii_data<=disp_write_cache[disp_cache_start];
|
|
disp_cache_start<=disp_cache_start+8'd1;
|
|
ascii_data_write_req<=1;
|
|
ascii_state<=1'b1;
|
|
end
|
|
end
|
|
|
|
if(ascii_state==1'b1)begin
|
|
if(!ascii_data_ready)begin
|
|
ascii_data_write_req<=0;
|
|
ascii_state<=1'b0;
|
|
end
|
|
end
|
|
end
|
|
|
|
wire I2C_SPEED=counter[7];
|
|
|
|
|
|
wire [15:0]boot_rom_data_bus_read;
|
|
wire [15:0]boot_rom_data_bus_write;
|
|
|
|
assign boot_rom_data_bus_write=data_bus_write;
|
|
|
|
wire boot_rom_cs_n;
|
|
|
|
doublemem #( .RAM_SIZE_IN_BYTES(2048) ) boot_rom
|
|
( address_bus[10:0],boot_rom_data_bus_read,boot_rom_data_bus_write,rd,wr,BHE,boot_rom_cs_n,CPU_SPEED );
|
|
|
|
/// Memory Map
|
|
|
|
assign data_bus_read = ( IOMEM == 1 ) ? data_bus_read_IO : data_bus_read_MEM ;
|
|
wire [15:0] data_bus_read_IO = ( address_bus[7:1] == 7'h10 ) ? LITEDRAM_STATUS_REGISTER : ( (address_bus[7:4] == 4'h4) ? Wishbone_driver_data_bus_read:CPU_I2C_data_bus_read);
|
|
|
|
|
|
assign boot_rom_cs_n = !((IOMEM==0)&&(address_bus[15:12]==4'hF));
|
|
|
|
wire [15:0] data_bus_read_MEM = (address_bus[15:12]==4'hF)? boot_rom_data_bus_read:data_bus_read_DDR3;
|
|
|
|
wire DDR3_ram_cs = (IOMEM==0)&&(address_bus[15:12]!=4'hF);
|
|
//
|
|
// 0x20 | DDR STATUS BYTE1 |
|
|
// 0x21 | DDR STATUS BYTE1 |
|
|
// | |
|
|
// - | -- |
|
|
// | |
|
|
// 0x30 | WISHBONE |
|
|
// .. | .. |
|
|
// 0x3F | WISHBONE |
|
|
//
|
|
assign wishbone_cs=!((IOMEM==1)&&(address_bus[7:4] == 4'h4));
|
|
assign i2c_cs= !((IOMEM==1)&&(address_bus[7:4] == 4'h6));
|
|
|
|
assign wait_state_I2C=(i2c_cs==1'b0&&rd==1'b0)^i2c_cs_1d;
|
|
|
|
reg i2c_cs_1d;
|
|
|
|
always @(posedge CPU_SPEED)begin
|
|
i2c_cs_1d<=(i2c_cs==1'b0&&rd==1'b0);
|
|
end // TODO: Probably would need to so the same for the wishbone IO
|
|
|
|
wire wait_state_I2C;
|
|
/// DDR3 Controller
|
|
|
|
wire ddr3_init_done,ddr3_init_error,ddr3_pll_locked;
|
|
/* verilator lint_off UNUSEDSIGNAL */
|
|
wire user_rst;
|
|
/* verilator lint_on UNUSEDSIGNAL */
|
|
`ifndef SYNTHESIS
|
|
assign ddr3_pll_locked=1;
|
|
wire sim_trace;
|
|
assign sim_trace=0;//signal is not connected on litedram, not sure what was the idea behind it
|
|
`endif
|
|
|
|
wire [15:0]Wishbone_driver_data_bus_read;
|
|
wire [15:0]Wishbone_driver_data_bus_write=data_bus_write;
|
|
|
|
wire wishbone_cs;
|
|
|
|
Wishbone_IO_driver Wishbone_IO_driver(
|
|
///// GENERAL //////
|
|
.clock(CPU_SPEED),
|
|
.reset_n(reset),
|
|
|
|
////// CPU INTERFACE ///////
|
|
.address(address_bus[3:1]),
|
|
.data_bus_in(Wishbone_driver_data_bus_write),
|
|
.data_bus_out(Wishbone_driver_data_bus_read),
|
|
.read_n(rd),
|
|
.write_n(wr),
|
|
.chip_select_n(wishbone_cs),
|
|
|
|
////// WISHBONE INTERFACE /////
|
|
.wb_ctrl_ack(wb_ctrl_ack),
|
|
.wb_ctrl_adr(wb_ctrl_adr),
|
|
.wb_ctrl_cyc(wb_ctrl_cyc),
|
|
.wb_ctrl_err(wb_ctrl_err),
|
|
.wb_ctrl_sel(wb_ctrl_sel),
|
|
.wb_ctrl_stb(wb_ctrl_stb),
|
|
.wb_ctrl_we(wb_ctrl_we),
|
|
.wb_ctrl_bte(wb_ctrl_bte),
|
|
.wb_ctrl_cti(wb_ctrl_cti),
|
|
.wb_ctrl_dat_r(wb_ctrl_dat_r),
|
|
.wb_ctrl_dat_w(wb_ctrl_dat_w)
|
|
);
|
|
|
|
|
|
wire [15:0] LITEDRAM_STATUS_REGISTER = { 13'd0, ddr3_pll_locked ,ddr3_init_error, ddr3_init_done };
|
|
wire [15:0] data_bus_read_DDR3;
|
|
|
|
Wishbone_memory_driver Wishbone_memory_driver(
|
|
///// GENERAL //////
|
|
.clock(CPU_SPEED),
|
|
.reset_n(reset),
|
|
|
|
////// CPU INTERFACE ///////
|
|
.address(address_bus),
|
|
.BHE(BHE),
|
|
.data_bus_in(data_bus_write),
|
|
.data_bus_out(data_bus_read_DDR3),
|
|
.wait_state(wait_state_WBIO),
|
|
.read_n(rd),
|
|
.write_n(wr),
|
|
.chip_select_n(!(DDR3_ram_cs&&ddr3_init_done)),
|
|
|
|
////// WISHBONE INTERFACE /////
|
|
.wb_mem_ack(wb_mem_ack),
|
|
.wb_mem_adr(wb_mem_adr),
|
|
.wb_mem_cyc(wb_mem_cyc),
|
|
.wb_mem_err(wb_mem_err),
|
|
.wb_mem_sel(wb_mem_sel),
|
|
.wb_mem_stb(wb_mem_stb),
|
|
.wb_mem_we(wb_mem_we),
|
|
.wb_mem_data_r(wb_mem_data_r),
|
|
.wb_mem_data_w(wb_mem_data_w)
|
|
);
|
|
|
|
wire wait_state;
|
|
assign wait_state=wait_state_WBIO||wait_state_I2C;
|
|
wire wait_state_WBIO;
|
|
|
|
wire wb_ctrl_ack;
|
|
wire [29:0] wb_ctrl_adr;
|
|
wire [1:0] wb_ctrl_bte;
|
|
wire [2:0] wb_ctrl_cti;
|
|
wire wb_ctrl_cyc;
|
|
wire [31:0] wb_ctrl_dat_r;
|
|
wire [31:0] wb_ctrl_dat_w;
|
|
wire wb_ctrl_err;
|
|
wire [3:0] wb_ctrl_sel;
|
|
wire wb_ctrl_stb;
|
|
wire wb_ctrl_we;
|
|
|
|
wire wb_mem_ack;
|
|
wire [24:0] wb_mem_adr;
|
|
wire wb_mem_cyc;
|
|
wire [31:0] wb_mem_data_r;
|
|
wire [31:0] wb_mem_data_w;
|
|
wire wb_mem_err;
|
|
wire [3:0] wb_mem_sel;
|
|
wire wb_mem_stb;
|
|
wire wb_mem_we;
|
|
|
|
litedram_core DDR3_RAM_DRIVER(
|
|
////// GENERAL ///////
|
|
.clk(clk48),
|
|
.user_clk(CPU_SPEED),
|
|
`ifdef SYNTHESIS
|
|
.rst(!reset),
|
|
.pll_locked(ddr3_pll_locked),
|
|
`else
|
|
.sim_trace(sim_trace),
|
|
`endif
|
|
|
|
////// DDR3 INTERFACE //////
|
|
`ifdef SYNTHESIS
|
|
.ddram_a(ddram_a[12:0]), //also ignored on the litedram core
|
|
.ddram_ba(ddram_ba),
|
|
.ddram_cas_n(ddram_cas_n),
|
|
.ddram_cke(ddram_cke),
|
|
.ddram_clk_n(1'b0), // goes nowhere ...
|
|
.ddram_clk_p(ddram_clk_p),
|
|
.ddram_cs_n(ddram_cs_n),
|
|
.ddram_dm(ddram_dm),
|
|
.ddram_dq(ddram_dq),
|
|
.ddram_dqs_n(2'b00), // goes nowhere ...
|
|
.ddram_dqs_p(ddram_dqs_p),
|
|
.ddram_odt(ddram_odt),
|
|
.ddram_ras_n(ddram_ras_n),
|
|
.ddram_reset_n(ddram_reset_n),
|
|
.ddram_we_n(ddram_we_n),
|
|
`endif
|
|
|
|
/////// SYSTEM MEMORY INTERFACE ////////////////
|
|
.init_done(ddr3_init_done),
|
|
.init_error(ddr3_init_error),
|
|
.user_port_wishbone_0_ack(wb_mem_ack),
|
|
.user_port_wishbone_0_adr(wb_mem_adr),
|
|
.user_port_wishbone_0_cyc(wb_mem_cyc),
|
|
.user_port_wishbone_0_dat_r(wb_mem_data_r),
|
|
.user_port_wishbone_0_dat_w(wb_mem_data_w),
|
|
.user_port_wishbone_0_err(wb_mem_err),
|
|
.user_port_wishbone_0_sel(wb_mem_sel),
|
|
.user_port_wishbone_0_stb(wb_mem_stb),
|
|
.user_port_wishbone_0_we(wb_mem_we),
|
|
.user_rst(user_rst),
|
|
|
|
/////// WISHBONE CONTROL INTERFACE ///////////
|
|
.wb_ctrl_ack(wb_ctrl_ack),
|
|
.wb_ctrl_adr(wb_ctrl_adr),
|
|
.wb_ctrl_cyc(wb_ctrl_cyc),
|
|
.wb_ctrl_err(wb_ctrl_err),
|
|
.wb_ctrl_sel(wb_ctrl_sel),
|
|
.wb_ctrl_stb(wb_ctrl_stb),
|
|
.wb_ctrl_we(wb_ctrl_we),
|
|
.wb_ctrl_bte(wb_ctrl_bte),
|
|
.wb_ctrl_cti(wb_ctrl_cti),
|
|
.wb_ctrl_dat_r(wb_ctrl_dat_r),
|
|
.wb_ctrl_dat_w(wb_ctrl_dat_w)
|
|
);
|
|
|
|
wire [15:0]CPU_I2C_data_bus_read;
|
|
wire i2c_cs;
|
|
|
|
wire [6:0] CPU_I2C_OUT_ADDRESS;
|
|
wire CPU_I2C_OUT_BUSY,CPU_I2C_OUT_TRANSACT,CPU_I2C_DIR;
|
|
wire [15:0]CPU_I2C_DATA_READ,CPU_I2C_DATA_WRITE;
|
|
wire CPU_I2C_IGN_ACK;
|
|
|
|
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;
|
|
reg ascii_data_write_req=0;
|
|
reg [7:0] ascii_data;
|
|
ascii_to_HD44780_driver LCD_DRIVER(
|
|
/* system */
|
|
I2C_SPEED,
|
|
1'b1,
|
|
|
|
/* Data Input */
|
|
ascii_data_ready,
|
|
ascii_data_write_req,
|
|
ascii_data,
|
|
|
|
/* write circuitry */
|
|
!pcf_busy,
|
|
pcf_write_req,
|
|
pcf_data,
|
|
pcf_command_data
|
|
);
|
|
|
|
// Port expander driver
|
|
|
|
wire pcf_write_req,pcf_command_data,pcf_busy;
|
|
wire [3:0]pcf_data;
|
|
/* verilator lint_off UNUSEDSIGNAL */
|
|
wire [7:0]DISP_I2C_DATA_WRITE;
|
|
wire [15:0]DISP_I2C_DATA_READ;
|
|
/* verilator lint_on UNUSEDSIGNAL */
|
|
wire DISP_I2C_BUSY,DISP_I2C_TRANSACT;
|
|
wire [6:0] DISP_I2C_ADDRESS;
|
|
assign DISP_I2C_ADDRESS=7'h27;
|
|
wire DISP_DIR;
|
|
|
|
pcf8574_for_HD44780 PCF8574_driver(
|
|
.clock(I2C_SPEED),
|
|
|
|
.pcf_write_req(pcf_write_req),
|
|
.pcf_command_data(pcf_command_data),
|
|
.pcf_data(pcf_data),
|
|
|
|
.pcf_busy(pcf_busy),
|
|
.new_backlight(1'b0),
|
|
.backlight_update(1'b0),
|
|
|
|
.DIR(DISP_DIR),
|
|
.I2C_BUSY(DISP_I2C_BUSY),
|
|
.I2C_TRANSACT(DISP_I2C_TRANSACT),
|
|
|
|
.i2c_data_write(DISP_I2C_DATA_WRITE)
|
|
);
|
|
|
|
wire [6:0]MULT_TO_DRIV_I2C_ADDRESS;
|
|
wire MULT_TO_DRIV_I2C_BUSY;
|
|
wire MULT_TO_DRIV_I2C_TRANSACT;
|
|
wire [15:0]MULT_TO_DRIV_DATA_WRITE, MULT_TO_DRIV_DATA_READ;
|
|
wire MULT_TO_DRIV_DIR;
|
|
wire CPU_I2C_TRANS_WIDTH;
|
|
|
|
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;
|
|
wire MULT_TO_DRIV_TRANS_WIDTH;
|
|
wire MULT_TO_DRIV_IGN_ACK;
|
|
|
|
I2C_driver i2c_driver(
|
|
.clock(I2C_SPEED),
|
|
|
|
.SDA_input(SDA_input),
|
|
.SDA_output(SDA_output),
|
|
.SDA_direction(SDA_direction),
|
|
.SCL(SCL),
|
|
|
|
.address(MULT_TO_DRIV_I2C_ADDRESS),
|
|
.I2C_BUSY(MULT_TO_DRIV_I2C_BUSY),
|
|
.I2C_TRANSACT(MULT_TO_DRIV_I2C_TRANSACT),
|
|
.DIR(MULT_TO_DRIV_DIR),
|
|
.i2c_data_write(MULT_TO_DRIV_DATA_WRITE),
|
|
.i2c_data_read(MULT_TO_DRIV_DATA_READ),
|
|
|
|
.transact_width(MULT_TO_DRIV_TRANS_WIDTH),
|
|
.ignore_ack(MULT_TO_DRIV_IGN_ACK)
|
|
);
|
|
|
|
`ifdef SYNTHESIS
|
|
|
|
TRELLIS_IO #(
|
|
// Parameters.
|
|
.DIR ("BIDIR")
|
|
) TRELLIS_IO_00 (
|
|
// pin
|
|
.B (i2c_sda),
|
|
//input
|
|
.I (1'd0),
|
|
//Direction
|
|
.T (~( SDA_direction & (~SDA_output) )),
|
|
// Output
|
|
.O (SDA_input)
|
|
);
|
|
|
|
assign i2c_scl=SCL;
|
|
|
|
`else
|
|
|
|
assign i2c_dir=SDA_direction;
|
|
assign i2c_scl=SCL;
|
|
assign SDA_input=i2c_sda_in;
|
|
assign i2c_sda_out=SDA_output;
|
|
|
|
`endif
|
|
|
|
|
|
endmodule
|