entity Second(clk: in, ready: out) { let index: uint{..1200000} = 0; on clk.posedge { if index == 12000000 - 1 { ready <= 1; } else { index <= index + 1; ready <= 0; } } } entity Half(clk: in, ready: out) { let index: uint{..1200000} = 0; on clk.posedge { if index == 10000000 - 1 { ready <= 1; } else { index <= index + 1; ready <= 0; } } } entity MiniCounter(clk: in, rst: in, ready: out) { let index: uint{..400} = 0; on clk.posedge { if !rst { ready <= 0; index <= 0; } else { if index == 240 - 1 { ready <= 1; } else { index <= index + 1; ready <= 0; } } } } entity SpiMaster( rst: in, clk: in, tx_trigger: in, tx_ready: out, tx_byte: in[8], rx_byte: out[8], spi_clk: out, spi_tx: out, spi_rx: in, ) { let live_clk: bit[1] = 0; // Internal signals. let read_index: uint{0..8} = 0; let internal_clk: bit[1] = 0; let _FSM: bit[32] = 0; // Generate SPI signal from internal clock + SPI state. always { // if live_clk { // spi_clk = internal_clk; // } else { spi_clk = live_clk && internal_clk; // } } // Generate divided SPI clock. let div_idx: uint{..40} = 0; on clk.negedge { if !rst { div_idx <= 0; internal_clk <= 0; } else { if div_idx == 40 - 1 { internal_clk <= !internal_clk; div_idx <= 0; } else { div_idx <= div_idx + 1; } } } // Sample read values from positive clock edge. on internal_clk.posedge { rx_byte[read_index] <= spi_rx; } let transmitting = 0; let transmit_save = 1; on clk.posedge { if !rst { tx_ready <= 0; transmit_save <= 1; } else { // if tx_trigger is high, and we are not transmitting, start if transmit_save == transmitting { tx_ready <= 1; transmit_save <= !transmitting; } else if tx_trigger { tx_ready <= 0; } } } // SPI output state machine. on internal_clk.negedge { fsm { // Wait for transition trigger. spi_tx <= 0; await tx_ready == 0; // Enable output clock. live_clk <= 1; // Start sequence. read_index <= 7; spi_tx <= tx_byte[7]; yield; // Write bits. while read_index > 0 { spi_tx <= tx_byte[read_index - 1]; read_index <= read_index - 1; yield; } // Disable output clock. live_clk <= 0; transmitting <= !transmitting; // Loop forever. //loop { // yield; //} } } } entity Ethernet( rst: in, tx_clk: in, LED1: out, LED2: out, LED3: out, LED4: out, CS: out, spi_bit: out, // MOSI spi_rx: in, // MISO spi_clk: out, ) { let tx_valid = 0; let tx_byte: bit[8] = 0; let spi_ready; let spi_rx_value: bit[8]; let spi = SpiMaster { rst: rst, clk: tx_clk, tx_trigger: tx_valid, tx_ready: spi_ready, tx_byte: tx_byte, rx_byte: spi_rx_value, spi_clk: spi_clk, spi_tx: spi_bit, spi_rx: spi_rx }; let sleep_counter: uint{..1200000} = 0; const ERCRU = 0x20; const EWCRU = 0x22; const EEUDASTL = (0x16 | 0x00); const ESSETETHRST = 0b11001010; const EECON2L = (0x0E | 0x60); const EERXSTL = (0x04 | 0x00); const EMAMXFLL = (0x0A | 0x40); const EERXTAILL = (0x06 | 0x00); const EMAADR3L = (0x00 | 0x60); const EMAADR3H = (0x01 | 0x60); const EMAADR2L = (0x02 | 0x60); const EMAADR2H = (0x03 | 0x60); const EMAADR1L = (0x04 | 0x60); const EMAADR1H = (0x05 | 0x60); const ESENABLERX = 0b11101000; const ERCR = 0x00; const EESTATL = (0x1A | 0x00); const EERXRDPTL = (0x8A); const ERRXDATA = 0b00101100; let mini_delay_trigger; let mini_delay_result; let mini_delay = MiniCounter { clk: tx_clk, rst: mini_delay_trigger, ready: mini_delay_result, }; #define do_mini_delay mini_delay_trigger <= 1; await mini_delay_result; mini_delay_trigger <= 0 #define do_cs_toggle tx_valid <= 0; yield; CS <= 1; mini_delay_trigger <= 1; await mini_delay_result; mini_delay_trigger <= 0; CS <= 0; tx_valid <= 1 #define write_16(reg, A, B) \ tx_byte <= EWCRU; \ await spi_ready; \ tx_byte <= reg; \ await spi_ready; \ tx_byte <= A; \ await spi_ready; \ tx_byte <= B; \ await spi_ready #define read_16(reg, A, B) \ tx_byte <= ERCRU; \ await spi_ready; \ tx_byte <= reg; \ await spi_ready; \ await spi_ready; \ A <= spi_rx_value; \ await spi_ready; \ B := spi_rx_value #define write_byte(reg) \ tx_byte <= reg; \ await spi_ready #define read_byte(reg) \ await spi_ready; \ reg <= spi_rx_value #define read_byte_imm(reg) \ await spi_ready; \ reg := spi_rx_value let received: bit[16] = 0; let NextPacketPointerL: bit[8] = 0x40; let NextPacketPointerH: bit[8] = 0x53; let _FSM: bit[9] = 0; let checksumL: bit[8] = 0; let checksumH: bit[8] = 0; let dummy: bit[8] = 0; let status_vector: bit[8] = 0; on tx_clk.negedge { if !rst { CS <= 1; _FSM <= 0; tx_valid <= 0; } else { fsm { LED1 <= 1; CS <= 0; tx_valid <= 1; // enc424j600_init() write_16(EEUDASTL, 0x34, 0x12); do_cs_toggle; read_16(EEUDASTL, checksumL, checksumH); if checksumL == 0x34 && checksumH == 0x12 { LED2 <= 1; } do_cs_toggle; write_byte(ESSETETHRST); tx_valid <= 0; sleep_counter := 0; while sleep_counter < 360 { sleep_counter := sleep_counter + 1; yield; } yield; tx_valid <= 1; write_16(EECON2L, 0x00, 0xCB); // (magic number) do_cs_toggle; write_16(EERXSTL, 0x40, 0x53); // RX_BUFFER_START 0x5340 do_cs_toggle; write_16(EMAMXFLL, 0x42, 0x02); // MAX_FRAMELEN 0x0242 do_cs_toggle; write_16(EERXTAILL, 0xFE, 0x5F); // (magic number) do_cs_toggle; // Read MAC address read_16(EMAADR1L, dummy, dummy); // MAC 0:1 do_cs_toggle; read_16(EMAADR2L, dummy, dummy); // MAC 2:3 do_cs_toggle; read_16(EMAADR3L, dummy, dummy); // MAC 4:5 do_cs_toggle; write_byte(ESENABLERX); //Memory configuration //The ENC424j600 has 0x6000 (24kB) bytes of memory //We have to make good use of it. // 0x0000 // [Scratchpad] // 0x0400 // [TCP packets (578+42)*TCP_SOCKETS // 0x1b84 (assuming 10 sockets) // [unused area] // 0x5340 (RX_BUFFER_START (0x6000-RX_BUFFER_SIZE)) // [RX Buffer] // 0x6000 (End of standard SRAM) NextPacketPointerL <= 0x40; NextPacketPointerH <= 0x53; // enc424j600_recvpack() loop { do_cs_toggle; write_byte(ESENABLERX); do_cs_toggle; write_byte(ERCR | EESTATL); read_byte_imm(dummy); if dummy > 0 { //Configure ERXDATA for reading. do_cs_toggle; write_16(EERXRDPTL, NextPacketPointerL, NextPacketPointerH); do_cs_toggle; //Start reading!!! write_byte(ERRXDATA); // Read next packet pointer. read_byte(NextPacketPointerL); read_byte(NextPacketPointerH); // Read received byte count. read_byte(received[0:8]); read_byte(received[8:16]); read_byte_imm(status_vector); read_byte(dummy); if status_vector & (1 << 7) { LED3 <= 1; // Good packet. read_byte(dummy); read_byte(dummy); } // else { // ERROR: Bad packet // I have never observed tis code getting called, even when I saw dropped packets. // } } tx_valid <= 0; yield; } CS <= 1; loop { yield; } } } } } entity Main( clk: in, LED1: out, LED2: out, LED3: out, LED4: out, LED5: out, PMOD1: out, PMOD2: out, PMOD3: in, PMOD4: out, PMOD7: out, //PMOD8: out, //PMOD9: out, //PMOD10: out, ) { // PMOD1 = CS // PMOD2 = MOSI // PMOD3 = MISO // PMOD4 = SCLK let ready; let sec = Second { clk: clk, ready: ready }; let half = Half { clk: clk, ready: PMOD7 }; let ether = Ethernet { rst: ready, tx_clk: clk, LED1: LED1, LED2: LED2, LED3: LED3, LED4: LED4, CS: PMOD1, spi_bit: PMOD2, spi_rx: PMOD3, spi_clk: PMOD4, }; always { LED5 = !ready; } }