/* TODO: - Add PnP configuration to ISA bridge - Enable EFB - SPI - SPI Flash - Timers - PLLs - UFM - Add a multi-master arbiter - Add steering logic - 16 bit access to an 8 bit device initiates to two 8 bit cycles and reassembly of the bits - 8 bit access to a 16 bit device initates one 16 bit cycle with the wb_sel signal specified by address bit 0 and if odd, steers the upper byte lane back to the lower path. - SPI slave state machine. - MCU asserts slave select. This resets the slave state machine for new transfer. - The slave select signal is open drain w/ a pullup - MCU clocks in a series of bits into a shift register in machine. This holds the parameters of the pending transfer. At some point during this period (sufficiently past the initial clock), the slave machine drives the slave line down and the MCU high-z's. - Once the last bit is clocked in, the state machine initiates the transfer. - Once the transfer is finished, the slave releases the select line. - When the master see's the release, it drives out additional clock pulses to read the status and/or transfer result. -> To move a full block of data, I need a way the master MCU can initiate a burst of bytes while holding the master bus. - Alternate SPI slave machine - Use true dual ported EBR for both the emulation register file and for the raw block storage. - Map side A to a wishbone address or alternate translation unit on the ISA side. - Implement a mechanism similar to the above to read and write to an address in the file. - Reads: MCU asserts SS and the first n bytes index the starting address. Subsequent clocks read back bytes with auto address increment - Writes: MCU asserts SS and the first n bytes index the starting address. Subsequent clocks write into EBR with auto address increment - Third alternate SPI slave mechanism. - In order to pipe-line transfers efficiently, when transfering whole blocks from PC to MCU and visa versa, a dual ported FIFO is used so the MCU can read data as it's being written and can push data ahead of the PC reading it. The IRQ line can be repurposed for a FIFO empty/full flag during block transfers. I'm just not sure how that would be handled on the PC side. It would either need a state machine to unroll it, or in the case of IDE, wait until the whole block is present in the fifo and then trigger the PC to come read sequentially from the data register. - Pull all the pmi directives out of the lm8 code and implement a vendor file. - Reimplement the register file and adder with verilog primatives. - Add a wrapper around EBRs */ `include "system_conf.v" module ems_cpld_top ( // buffered ISA signals input isa_RESETn, // ISA reset inout [7:0] isa_D, // ISA data bus (x8) input [19:0] isa_SA, // ISA system address bus (x20) output isa_IOCHRDY, // ISA I/O channel ready input isa_SMEMWn, // ISA system memory write input isa_SMEMRn, // ISA system memory read input isa_IOWn, // ISA I/O write input isa_IORn, // ISA I/O read output [2:0] isa_IRQSEL, // ISA interrupt request select input isa_AEN, // ISA DMA address enable // Misc input xo_CLK, // SYS 26.00 MHz external XO input sys_CFGn, // Normal vs config mode (DIP SW) output sys_LED, // FPGA controlled single LED // Floppy Drive Controller (FDC) input fdc_RY_DCHG, // Ready/Disc Changed input fdc_RD_DATA, // Read Data input fdc_WR_PROT, // input fdc_INDEX, // input fdc_DENSITYi, // input fdc_TRACK0, // output fdc_SIDESEL, // output fdc_WRGATE, // output fdc_WRDATA, // output fdc_STEP, // output fdc_STEPDIR, // output fdc_MOTEN, // output fdc_DS0, // output fdc_DS1, // output fdc_DS2, // output fdc_DS3, // output fdc_IN_USE, // output fdc_DENSITYo, // // SPI flash //output spi_CLK, // SPI bit clock //output spi_MOSI, // SPI master out / slave in //input spi_MISO, // SPI master in / slave out //output spi_SSn, // SPI chip select // MCU IPC interface (SPI based) input mcu_CLK, // MCU bit clock input mcu_MOSI, // MCU master out / slave in output mcu_MISO, // MCU master in / slave out inout mcu_SSn, // MCU chip select / ready output mcu_IRQn, // MCU interrupt request // UART input com_RX, // UART receive output com_TX, // UART transmit input com_CTSn, // UART clear to send output com_RTSn, // UART ready to send // 64MB SDR SDRAM output [12:0] dram_A, // DRAM address bus (x13) inout [15:0] dram_DQ, // DRAM data bus (x16) output [1:0] dram_BA, // DRAM bank address (x2) output [1:0] dram_DQMn, // DRAM write data mask (x2) output dram_RASn, // DRAM row address strobe output dram_CASn, // DRAM column address strobe output dram_CSn, // DRAM chip select output dram_WEn, // DRAM write enable output dram_CLK, // DRAM clock output dram_CKE // DRAM clock enable ); /* * Clock tree setup. At the moment the board is stuffed with * a single 26 MHz external oscillator. Until this is changed, * use it to generate an semi-accurate clock for RAM, UART and * other functional clocks. The primary PLL generates a 39 MHz * functional RAM clock with a 90 deg phase shifted complement, * a 14.718 MHz functional UART clock close enough for division * to standard baud rates, and a 20 MHz clock that is cascaded * into the second PLL to generate a higher frequency functional * and interface clocks for the rest of the system. * * WARNING: Be very careful of the routing skew when mixing and * matching of different clocks. */ wire [1:0] pll_LOCK; // PLL lock output wire sdram_FCLK; // x30/20 (39 MHz) wire sdram_FCLK_90; // x30/20 (39 MHz) shifted +90 deg @ 50% duty wire cascade_CLK; // x30/53 (20 MHz) base functional clock wire uart_FCLK; // x30/39 (14.716981 MHz) UART base clock pll0 pll0 ( .CLKI(xo_CLK), .CLKOP(sdram_FCLK), .CLKOS(sdram_FCLK_90), .CLKOS2(uart_FCLK), .CLKOS3(cascade_CLK), .LOCK(pll_LOCK[0]) ); /* * The second PLL is in cascade and provides the primary clock * domain complete with a high speed functional base clock for * different systems (100 MHz), derivitives of it, and the main * system clock (33.3 MHz). */ wire hs_FCLK; // x30/6 (100 MHz) wire hs2_FCLK; // x30/15 (40 MHz) wire hs3_FCLK; // x30/30 (20 MHz - phase aligned) wire sys_CLK; // x30/18 (33.33 MHz) pll1 pll1 ( .CLKI(cascade_CLK), .CLKOP(hs_FCLK), .CLKOS(sys_CLK), .CLKOS2(hs2_FCLK), .CLKOS3(hs3_FCLK), .LOCK(pll_LOCK[1]) ); // System signals wire sys_RESET; //assign sys_RESET = !isa_RESETn && !pll_LOCK; assign sys_RESET = !pll_LOCK[0];//!isa_RESETn; assign sys_LED = pll_LOCK[0];//sys_RESET; wire [11:0] la; assign fdc_DENSITYo = la[0]; assign fdc_IN_USE = la[1]; assign fdc_DS3 = la[2]; assign fdc_DS0 = la[3]; assign fdc_DS1 = la[4]; assign fdc_DS2 = la[5]; assign fdc_MOTEN = la[6]; assign fdc_STEPDIR = la[7]; assign fdc_STEP = la[8]; assign fdc_WRDATA = la[9]; assign fdc_WRGATE = la[10]; assign fdc_SIDESEL = la[11]; assign la[0] = fdc_RY_DCHG; assign la[1] = isa_RESETn; assign la[2] = sdram_FCLK; assign la[3] = sdram_FCLK_90; assign la[4] = uart_FCLK; assign la[5] = cascade_CLK; assign la[6] = sys_CLK; assign la[7] = hs_FCLK; assign la[8] = hs2_FCLK; assign la[9] = hs3_FCLK; assign la[10] = pll_LOCK[0]; assign la[11] = pll_LOCK[1]; assign com_RTSn = xo_CLK; // add UFM control // Wishboneg wire wb_clk; wire wb_rst; wire [7:0] wb_dat_o; wire [7:0] wb_dat_i; wire [31:0] wb_adr; wire wb_we; wire wb_tga; // 1 = I/O, 0 = MEM wire wb_stb; wire wb_cyc; wire wb_ack; assign wb_clk = xo_CLK; // 26 MHz assign wb_rst = sys_RESET; wire isa_CS; isa_wb_master isa_bridge ( // ISA pads .isa_D (isa_D), .isa_SA (isa_SA), .isa_IOCHRDY (isa_IOCHRDY), .isa_SMEMW (~isa_SMEMWn), .isa_SMEMR (~isa_SMEMRn), .isa_IOW (~isa_IOWn), .isa_IOR (~isa_IORn), .isa_AEN (isa_AEN), .isa_CS (isa_CS), // Wishbone master interface .wb_clk_i (wb_clk), .wb_rst_i (wb_rst), .wb_dat_i (wb_dat_i), .wb_dat_o (wb_dat_o), .wb_adr_o (wb_adr), .wb_we_o (wb_we), .wb_tga_o (wb_tga), .wb_stb_o (wb_stb), .wb_cyc_o (wb_cyc), .wb_ack_i (wb_ack) ); assign isa_IRQSEL = 3'b000; /* assign fdc_SIDESEL = 1'b0; assign fdc_WRGATE = 1'b0; assign fdc_WRDATA = 1'b0; assign fdc_STEP = 1'b0; assign fdc_STEPDIR = 1'b0; assign fdc_MOTEN = 1'b0; assign fdc_DS0 = 1'b0; assign fdc_DS1 = 1'b0; assign fdc_DS2 = 1'b0; assign fdc_DS3 = 1'b0; assign fdc_IN_USE = 1'b0; assign fdc_DENSITYo = 1'b0; */ assign spi_CLK = 1'b1; assign spi_MOSI = 1'b1; assign spi_SSn = 1'b1; assign mcu_MISO = 1'b1; assign mcu_SSn = 1'b1; assign mcu_IRQn = 1'b1; assign dram_DQ = 16'b0000000000000000; assign dram_A = 13'b0000000000000; assign dram_BA = 2'b00; assign dram_DQMn = 2'b00; assign dram_RASn = 1'b0; assign dram_CASn = 1'b0; assign dram_CSn = 1'b0; assign dram_WEn = 1'b0; assign dram_CLK = 1'b0; assign dram_CKE = 1'b0; wire lm8_CLK; assign lm8_CLK = xo_CLK; // 26 MHz // LM8 Master Wishbone Bus Nets wire [31:0] LM8D_ADR_O; wire [7:0] LM8D_DAT_O; wire [7:0] LM8D_DAT_I; wire LM8D_SEL_O; wire LM8D_WE_O; wire LM8D_ACK_I; wire LM8D_ERR_I; wire LM8D_RTY_I; wire [2:0] LM8D_CTI_O; wire [1:0] LM8D_BTE_O; wire LM8D_LOCK_O; wire LM8D_CYC_O; wire LM8D_STB_O; // UART Wishbone Outputs - to be muxed wire uart_CS; wire [7:0] uart_DAT_O; wire uart_ACK_O; wire uart_ERR_O; wire uart_RTY_O; assign uart_CS = (LM8D_ADR_O[31:4] == 28'b10000000_00000000_00000000_0000); wire uart_IRQ; assign isa_CS = 1'b0; uart_core #( .UART_WB_DAT_WIDTH(8), .UART_WB_ADR_WIDTH(4), .CLK_IN_HZ(26000000), .BAUD_RATE(115200), .STDOUT_SIM(0), .STDOUT_SIMFAST(0), .LCR_DATA_BITS(8), .LCR_STOP_BITS(1), .LCR_PARITY_ENABLE(0), .LCR_PARITY_ODD(0), .LCR_PARITY_STICK(0), .LCR_SET_BREAK(0), .FIFO(0) ) uart ( .UART_ADR_I (LM8D_ADR_O[3:0]), .UART_DAT_I (LM8D_DAT_O), .UART_DAT_O (uart_DAT_O), .UART_SEL_I (LM8D_SEL_O), .UART_WE_I (LM8D_WE_O), .UART_ACK_O (uart_ACK_O), .UART_ERR_O (uart_ERR_O), .UART_RTY_O (uart_RTY_O), .UART_CTI_I (LM8D_CTI_O), .UART_BTE_I (LM8D_BTE_O), .UART_LOCK_I(LM8D_LOCK_O), .UART_CYC_I (LM8D_CYC_O & uart_CS), .UART_STB_I (LM8D_STB_O & uart_CS), .SIN (com_RX), .SOUT (com_TX), .DCD_N(1'b0), .CTS_N(com_CTSn), .DSR_N(1'b0), .RI_N (1'b0), .DTR_N(), .RTS_N(),//com_RTSn), .INTR (uart_IRQ), .CLK (lm8_CLK), .RESET(sys_RESET) ); assign LM8D_DAT_I = uart_CS ? uart_DAT_O : 8'b00000000; assign LM8D_ERR_I = LM8D_CYC_O & !(uart_CS & !uart_ERR_O); assign LM8D_ACK_I = uart_CS ? uart_ACK_O : 0; assign LM8D_RTY_I = uart_CS ? uart_RTY_O : 0; wire [7:0] LM8interrupts; lm8 #( .LATTICE_FAMILY("MachXO2"), .CFG_REGISTER_16(1), .CFG_REGISTER_32(0), .CFG_EXT_SIZE_8(0), .CFG_EXT_SIZE_16(1), .CFG_EXT_SIZE_32(0), .CFG_CALL_STACK_8(0), .CFG_CALL_STACK_16(1), .CFG_CALL_STACK_32(0), .CFG_PROM_SIZE(1024), .CFG_PROM_BASE_ADDRESS(32'h00000000), .CFG_PROM_INIT_FILE("lm8_src/bin/test_code.mem"), .CFG_PROM_INIT_FILE_FORMAT("hex"), .SP_SIZE(512), .SP_BASE_ADDRESS(32'h00000000), .CFG_SP_INIT_FILE("lm8_src/bin/test_data.mem"), .CFG_SP_INIT_FILE_FORMAT("hex"), .CFG_IO_BASE_ADDRESS(32'h80000000) ) lm8 ( .D_ADR_O (LM8D_ADR_O), .D_DAT_O (LM8D_DAT_O), .D_DAT_I (LM8D_DAT_I), .D_SEL_O (LM8D_SEL_O), .D_WE_O (LM8D_WE_O), .D_ACK_I (LM8D_ACK_I), .D_ERR_I (LM8D_ERR_I), .D_RTY_I (LM8D_RTY_I), .D_CTI_O (LM8D_CTI_O), .D_BTE_O (LM8D_BTE_O), .D_LOCK_O(LM8D_LOCK_O), .D_CYC_O (LM8D_CYC_O), .D_STB_O (LM8D_STB_O), .interrupts (LM8interrupts), .clk_i (lm8_CLK), .rst_i (sys_RESET) ); assign LM8interrupts[0] = uart_IRQ; assign LM8interrupts[1] = 0; assign LM8interrupts[2] = 0; assign LM8interrupts[3] = 0; assign LM8interrupts[4] = 0; assign LM8interrupts[5] = 0; assign LM8interrupts[6] = 0; assign LM8interrupts[7] = 0; endmodule