// $$$ : g2usb3.v -- G2 bus <=> USBN9603 (mode 0) interface version 3. // // used circuit: g2usbn9603_3.gif // used device: XC9572XL-VQ44 (Xilinx) // last update: 2006/10/30 // // device mapping: // base address + 0: USBN9603 data register (lower byte mapping) // base address + 2: USBN9603 adrs register (lower byte mapping) // base address + 1: GPIO port register (upper byte mapping) // base address + 3: CONTROL register (upper byte mapping) // CONTROL register: // bit[7] 'irqen' enable flag (read/write) // bit[6] 'intp' status (read) // bit[5:0] GPIO direction IN:1 / OUT:0 (read/write) // // history: // version 3: (circuit: g2usbn9603_3.gif) // use G2 bus /BTA /BTB signal. (bus access time control) // USBN9603 data bus to direct G2 bus (not enough terminal 'XC9572XL-VQ44') // add GPIO port P5 - P0 (6bit) // add device enable/disable logic (use magic code) // enable: write word MAGIC_CODE // disable: write long word MAGIC_CODE // add internal reset (use 'magic_valid' flag) // // version 2: (circuit: g2usbn9603_2.gif) // change G2 bus signal name (dir => lben / den => uben) // device address mapping: from long word align to byte align // device access: from word access to byte access // // date 2006/10/19 designed by jj1odm `timescale 1ns / 1ps module g2usb3( input clk, // G2 bus system clock (25MHz) input aen, // G2 bus address enable (active low) input lben, // G2 bus direction and lower byte enable (active low) [change name: dir => lben] input uben, // G2 bus upper byte enable (active low) [change name: den => uben] inout [15:0] ad, // G2 bus address/data multiplexed bus (16 bit) output btan, // G2 bus bus termination A (active low) output btbn, // G2 bus bus termination B (active low) output irqn, // G2 bus interrupt (open drain active low) output csn, // USBN9603 chip select (active low) output a0, // USBN9603 a0 address (data/adrs register select) output rdn, // USBN9603 read strobe (active low) output wrn, // USBN9603 write strobe (active low) input intp, // USBN9603 interrupt (active high) inout [5:0] p // GPIO port (6 bit) ); parameter IOBASE_HIGH = 13'h1400; // I/O base high word address parameter IOBASE_LOW = 14'b00000000000000; // I/O base low word address parameter MAGIC_CODE = 16'h4b46; // magic code (my initial name 'KF') parameter G2_IDLE = 2'b00; // G2 bus idle state parameter G2_HI_ADDRESS = 2'b01; // G2 bus high address state parameter G2_DATA = 2'b11; // G2 bus data state parameter G2_END = 2'b10; // G2 bus end state parameter ACCESS_WIDTH = 0; // bus access width (ACCESS_WIDTH * 40nSEC) + 160nSEC reg magic_valid = 1'b0; // magic code valid flag register (init 0) reg [1:0] g2bus_state = G2_IDLE; // G2 bus state machine register (init G2_IDLE state) reg aen_old = 1'b1; // G2 bus cycle detect register (init '1') reg [3:0] wait_cnt = 4'b0000; // G2 bus wait counter (init 0) reg bus_end = 1'b1; // bus end flag (active low) reg [15:0] g2reg; // for g2 bus tri-state logic reg adrs; // 'AD1' address latch register (1bit) reg direction; // direction latch register reg irqen = 1'b0; // interrupt enable register (initial disable) reg [5:0] gpioreg = 6'b000000; // GPIO output port register (init 0) reg [5:0] gpiodir = 6'b111111; // GPIO direction control register (init all input) wire bus_valid; // bus cycle valid flag node wire bus_valid_2; // bus cycle valid 2 flag node wire [7:0] control_node; // control register node // control register node bit assign assign control_node[7] = irqen; // interrupt enable (bit 7) assign control_node[6] = intp; // assign 'intp' to (bit 6) assign control_node[5:0] = gpiodir; // bit [5:0] GPIO direction register // GPIO port assign assign p[5] = gpiodir[5] ? 1'bz : gpioreg[5]; // P5 assign p[4] = gpiodir[4] ? 1'bz : gpioreg[4]; // P4 assign p[3] = gpiodir[3] ? 1'bz : gpioreg[3]; // P3 assign p[2] = gpiodir[2] ? 1'bz : gpioreg[2]; // P2 assign p[1] = gpiodir[1] ? 1'bz : gpioreg[1]; // P1 assign p[0] = gpiodir[0] ? 1'bz : gpioreg[0]; // P0 // 'irqn' siganl assign assign irqn = (intp & irqen) ? 1'b0 : 1'bz; // assign 'irqn' // G2 bus termination control A/B (for byte access) assign btan = g2bus_state == G2_END ? bus_end : 1'bz; assign btbn = g2bus_state == G2_END ? bus_end : 1'bz; // USBN9603 interface node (lower byte access) assign bus_valid = magic_valid & (g2bus_state == G2_DATA | g2bus_state == G2_END); // bus valid flag assign bus_valid_2 = g2bus_state == G2_DATA | g2bus_state == G2_END; // bus valid 2 flag assign csn = ~(~lben & uben & bus_valid); // USBN9603 'csn' assign a0 = adrs; // USBN9603 'a0' assign rdn = ~(direction & ~lben & uben & bus_valid); // USBN9603 'rdn' assign wrn = ~(~direction & ~lben & uben & bus_valid); // USBN9603 'wrn' // G2 bus tri-state buffer & etc registers logic (upper byte access) assign ad = g2reg; always @(magic_valid or bus_valid_2 or uben or lben or direction or adrs or control_node or p or ad) begin if (magic_valid) begin if (bus_valid_2 & ~uben & lben) begin // upper byte access if (direction) begin // read g2reg[7:0] <= 8'hzz; if (adrs) g2reg[15:8] <= control_node; // read control register else g2reg[15:8] <= {2'b00, p}; // read GPIO port (msb 2bit always '0') end else begin // write g2reg <= 16'hzzzz; if (adrs) begin // control register irqen <= ad[15]; // write irqen bit (bit 7) gpiodir <= ad[13:8]; // write GPIO direction register end else gpioreg <= ad[13:8]; // write GPIO port register end end else g2reg <= 16'hzzzz; end else begin // internal reset: magic_valid == 0 then reset etc regs g2reg <= 16'hzzzz; irqen <= 1'b0; gpiodir <= 6'b111111; gpioreg <= 6'b000000; end end // G2 bus state machine (ignore: not this device or long word access) always @(posedge clk) begin aen_old <= aen; // for negtive edge detect 'aen' // idle state if (g2bus_state == G2_IDLE) begin // negtive edge detect 'aen' & equal IOBASE_LOW if (~aen & aen_old & ad[15:2] == IOBASE_LOW) begin adrs <= ad[1]; // 'AD1' (low word address) latch direction <= lben; // direcion latch wait_cnt <= 4'b0000; // init wait count bus_end <= 1'b1; // init bus end flag g2bus_state <= G2_HI_ADDRESS; // next state end end // high address state if (g2bus_state == G2_HI_ADDRESS) begin if (ad[12:0] == IOBASE_HIGH) g2bus_state <= G2_DATA; // this device then next state else g2bus_state <= G2_IDLE; // else return idle state end // data state if (g2bus_state == G2_DATA) begin if (~magic_valid) begin if (~adrs & ~uben & ~lben & aen & ~direction & ad == MAGIC_CODE) begin // IOBASE write MAGIC_CODE (word) then magic_valid <= 1'b1; // set 'magic_valid' flag (device enable) end g2bus_state <= G2_IDLE; // return idle state end else begin // magic_valid flag on then valid bus cycle if (~aen) begin // long word access if (~adrs & ~uben & ~lben & ~direction & ad == MAGIC_CODE) begin // IOBASE write MAGIC_CODE (long word) then magic_valid <= 1'b0; // clear 'magic_valid' flag (device disable) end g2bus_state <= G2_IDLE; // return idle state end else begin // normal bus access wait_cnt <= wait_cnt + 4'b0001; if (wait_cnt == ACCESS_WIDTH) begin // check bus wait count bus_end <= 1'b0; // bus_end active low g2bus_state <= G2_END; // next state end end end end // bus end state (for bus end pulse) if (g2bus_state == G2_END) begin bus_end <= 1'b1; // 1 clock bus_end high if (bus_end) begin // for fast rising edge (guard of hi-z) g2bus_state <= G2_IDLE; // return idle state end end end endmodule // end of : g2usb3.v