diff --git a/cores/mist/data_io.v b/cores/mist/data_io.v index f4c1243..d3ea79a 100644 --- a/cores/mist/data_io.v +++ b/cores/mist/data_io.v @@ -52,9 +52,13 @@ assign addr = (cmd==2)?(addrR[22:0]-23'd1):addrR[22:0]; // latch bus cycle to have it stable at the end of the cycle (rising edge of clk8) reg [1:0] bus_cycle_L; -always @(negedge clk_8) +always @(negedge clk_8) begin bus_cycle_L <= bus_cycle; + if(bus_cycle == 0) + br <= brI; +end + // generate state signals required to control the sdram host interface always @(posedge clk_8) begin // start io transfers clock cycles after bus_cycle 0 @@ -64,8 +68,6 @@ always @(posedge clk_8) begin readD <= readCmd && ((bus_cycle_L == 3) || readD); readD2 <= readD; - br <= brI; - // at the end of a read cycle latch the incoming ram data for later spi transmission if(read) ram_data <= data_in; diff --git a/cores/mist/mfp.v b/cores/mist/mfp.v index a09e124..d18c1c4 100644 --- a/cores/mist/mfp.v +++ b/cores/mist/mfp.v @@ -18,6 +18,10 @@ module mfp ( input serial_strobe_out, output [7:0] serial_data_out, + // serial rs223 connection from io controller + input serial_strobe_in, + input [7:0] serial_data_in, + // inputs input clk_ext, // external 2.457MHz input [1:0] t_i, // timer input @@ -27,17 +31,55 @@ module mfp ( localparam FIFO_ADDR_BITS = 4; localparam FIFO_DEPTH = (1 << FIFO_ADDR_BITS); -// +// fifo for data from mfp to io controller reg [7:0] fifoOut [FIFO_DEPTH-1:0]; reg [FIFO_ADDR_BITS-1:0] writePout, readPout; +// fifo for data from io-controller to mfp +reg [7:0] fifoIn [FIFO_DEPTH-1:0]; +reg [FIFO_ADDR_BITS-1:0] writePin, readPin; + assign serial_data_out_available = (readPout != writePout); assign serial_data_out = fifoOut[readPout]; +wire serial_data_in_available = (readPin != writePin) /* synthesis keep */; +wire [7:0] serial_data_in_cpu = serial_data_in_available?fifoIn[readPin]:fifoIn[readPin-4'd1]; + // signal "fifo is full" via uart config bit wire serial_data_out_fifo_full = (readPout === (writePout + 4'd1)); -// ---------------- send mfp uart data to io controller ------------ +// ---------------- mfp uart data to/from io controller ------------ +reg serial_strobe_inD, serial_strobe_inD2; +reg serial_cpu_data_read; + +always @(negedge clk) begin + serial_strobe_inD <= serial_strobe_in; + serial_strobe_inD2 <= serial_strobe_inD; + + // read on uart data register + serial_cpu_data_read <= 1'b0; + if(sel && ~ds && rw && (addr == 5'h17)) + serial_cpu_data_read <= 1'b1; + + if(reset) begin + // reset read and write counters + readPin <= 4'd0; + writePin <= 4'd0; + end else begin + // store bytes received from IO controller via SPI + if(serial_strobe_inD && !serial_strobe_inD2) begin + // store data in fifo + fifoIn[writePin] <= serial_data_in; + writePin <= writePin + 4'd1; + end + + // advance read pointer on every cpu read + if(serial_cpu_data_read && serial_data_in_available) + readPin <= readPin + 4'd1; + end +end + + reg serial_strobe_outD, serial_strobe_outD2; always @(posedge clk) begin serial_strobe_outD <= serial_strobe_out; @@ -184,6 +226,10 @@ wire [3:0] highest_irq_pending = // gpip as output to the cpu (ddr bit == 1 -> gpip pin is output) wire [7:0] gpip_cpu_out = (i & ~ddr) | (gpip & ddr); +// cpu controllable uart control bits +reg [1:0] uart_rx_ctrl; +reg [3:0] uart_tx_ctrl; + // cpu read interface always @(iack, sel, ds, rw, addr, gpip_cpu_out, aer, ddr, ier, ipr, isr, imr, vr, serial_data_out_fifo_full, timera_dat_o, timerb_dat_o, @@ -216,7 +262,9 @@ always @(iack, sel, ds, rw, addr, gpip_cpu_out, aer, ddr, ier, ipr, isr, imr, if(addr == 5'h12) dout = timerd_dat_o; // uart: report "tx buffer empty" if fifo is not full - if(addr == 5'h16) dout = serial_data_out_fifo_full?8'h00:8'h80; + if(addr == 5'h15) dout = { serial_data_in_available, 5'b00000 , uart_rx_ctrl}; + if(addr == 5'h16) dout = { !serial_data_out_fifo_full, 3'b000 , uart_tx_ctrl}; + if(addr == 5'h17) dout = serial_data_in_cpu; end else if(iack) begin dout = irq_vec; @@ -234,6 +282,8 @@ reg iackD; // latch to keep irq vector stable during irq ack cycle reg [7:0] irq_vec; +reg [1:0] usart_irqD; + always @(negedge clk) begin iackD <= iack; @@ -246,6 +296,10 @@ always @(negedge clk) begin iD <= aer ^ ((i & ~ti_irq_mask) | (ti_irq & ti_irq_mask)); iD2 <= iD; + // delay usart states to react on changes + usart_irqD[0] <= !serial_data_out_fifo_full; + usart_irqD[1] <= serial_data_in_available; + if(reset) begin ipr <= 16'h0000; ier <= 16'h0000; imr <= 16'h0000; isr <= 16'h0000; @@ -274,6 +328,10 @@ always @(negedge clk) begin if(!iD[5] && iD2[5] && ier[ 7]) ipr[ 7] <= 1'b1; // dma if(!iD[7] && iD2[7] && ier[15]) ipr[15] <= 1'b1; // mono detect + // output fifo just became "not full" or input fifo became "not empty" + if(!usart_irqD[0] && !serial_data_out_fifo_full && ier[10]) ipr[10] <= 1'b1; + if(!usart_irqD[1] && serial_data_in_available && ier[12]) ipr[12] <= 1'b1; + if(sel && ~ds && ~rw) begin if(addr == 5'h00) gpip <= din; if(addr == 5'h01) aer <= din; @@ -298,6 +356,10 @@ always @(negedge clk) begin if(addr == 5'h0a) imr[7:0] <= din; if(addr == 5'h0b) vr <= din; + + // ------- uart ------------ + if(addr == 5'h15) uart_rx_ctrl <= din[1:0]; + if(addr == 5'h16) uart_tx_ctrl <= din[3:0]; if(addr == 5'h17) begin fifoOut[writePout] <= din; diff --git a/cores/mist/mist_top.v b/cores/mist/mist_top.v index 2e369c5..28d6344 100644 --- a/cores/mist/mist_top.v +++ b/cores/mist/mist_top.v @@ -111,9 +111,9 @@ always @(posedge clk_8) begin dtack_timeout <= dtack_timeout + 4'd1; end end - end + end end - + // no tristate busses exist inside the FPGA. so bus request doesn't do // much more than halting the cpu by suppressing dtack `define BRWIRE @@ -305,11 +305,13 @@ mfp mfp ( .irq (mfp_irq ), .iack (mfp_iack ), - // serial/rs232 interface + // serial/rs232 interface io-controller<->mfp .serial_data_out_available (serial_data_from_mfp_available), .serial_strobe_out (serial_strobe_from_mfp), .serial_data_out (serial_data_from_mfp), - + .serial_strobe_in (serial_strobe_to_mfp), + .serial_data_in (serial_data_to_mfp), + // input signals .clk_ext (clk_mfp ), // 2.457MHz clock .t_i (mfp_timer_in ), // timer a/b inputs @@ -545,7 +547,7 @@ wire clk_8; wire clk_32; wire clk_128; wire clk_mfp; - + // use pll clock clock ( .areset (1'b0 ), // async reset input @@ -667,32 +669,17 @@ wire tg68_uds_S; wire tg68_lds_S; wire tg68_rw_S; reg tg68_as; -reg cpu_fast_cycle; // signal indicating that the cpu runs from cache - -always @(posedge clk_8) begin - // tg68 core does not provide a as signal, so we generate it - tg68_as <= (tg68_busstate != 2'b01) && !br; - - // all other output signals are simply latched to make sure - // they don't change within a 8Mhz cycle even if the CPU - // advances. This would be a problem if e.g. The CPU would try - // to start a bus cycle while the 8Mhz cycle is in progress - tg68_dat_out <= tg68_dat_out_S; - tg68_adr <= tg68_adr_S; - tg68_uds <= tg68_uds_S; - tg68_lds <= tg68_lds_S; - tg68_rw <= tg68_rw_S; - tg68_fc <= tg68_fc_S; -end +reg cpu_fast_cycle; // signal indicating that the cpu runs from cache, used to calm berr // the CPU throttle counter limits the CPU speed to a rate the tg68 core can // handle. With a throttle of "4" the core will run effectively at 32MHz which // is equivalent to ~64MHz on a real 68000. This speed will never be achieved // since memory and peripheral access slows the cpu further -localparam CPU_THROTTLE = 4'd5; +localparam CPU_THROTTLE = 4'd6; reg [3:0] clkcnt; - + reg trigger /* synthesis noprune */; +reg panic /* synthesis noprune */; always @(posedge clk_128) begin // count 0..15 within a 8MHz cycle @@ -707,11 +694,30 @@ always @(posedge clk_128) begin dCacheStore <= 1'b0; cacheUpdate <= 1'b0; trigger <= 1'b0; + panic <= 1'b0; + + if(clkcnt == 15) begin + // 8Mhz cycle must not start directly after the cpu has been clocked + // as the address may not be stable then + + // cpuDoes8MhzCycle has same timing as tg68_as + if(!clkena && !br) cpuDoes8MhzCycle <= 1'b1; - // cpuDoes8MhzCycle has same timing as tg68_as - if(clkcnt == 15) begin - cpuDoes8MhzCycle <= 1'b1; cpu_fast_cycle <= 1'b0; + + // tg68 core does not provide a as signal, so we generate it + tg68_as <= !clkena && (tg68_busstate != 2'b01) && !br; + + // all other output signals are simply latched to make sure + // they don't change within a 8Mhz cycle even if the CPU + // advances. This would be a problem if e.g. The CPU would try + // to start a bus cycle while the 8Mhz cycle is in progress + tg68_dat_out <= tg68_dat_out_S; + tg68_adr <= tg68_adr_S; + tg68_uds <= tg68_uds_S; + tg68_lds <= tg68_lds_S; + tg68_rw <= tg68_rw_S; + tg68_fc <= tg68_fc_S; end // evaluate cache one cycle before cpu is allowed to access the bus again @@ -731,6 +737,11 @@ always @(posedge clk_128) begin // cpu wants to read and the requested data is available from the cache -> run immediately if((tg68_busstate == 2'b01) || cacheRead) begin clkena <= 1'b1; + + // cpu must never try to fetch instructions from non-mem + if((tg68_busstate == 2'b00) && !cpu2mem) + panic <= 1'b1; + cpu_throttle <= CPU_THROTTLE; cpuDoes8MhzCycle <= 1'b0; cpu_fast_cycle <= 1'b1; @@ -747,6 +758,10 @@ always @(posedge clk_128) begin cpu_throttle <= CPU_THROTTLE; cpuDoes8MhzCycle <= 1'b0; + // cpu must never try to fetch instructions from non-mem + if((tg68_busstate == 2'b00) && !cpu2mem) + panic <= 1'b1; + // ---------- cache debugging --------------- // if the cache reports a hit, it should be the same data that's also // returned by ram. Otherwise the cache is broken @@ -1023,6 +1038,8 @@ wire ikbd_data_from_acia_available; wire [7:0] serial_data_from_mfp; wire serial_strobe_from_mfp; wire serial_data_from_mfp_available; +wire [7:0] serial_data_to_mfp; +wire serial_strobe_to_mfp; //// user io has an extra spi channel outside minimig core //// user_io user_io( @@ -1043,6 +1060,8 @@ user_io user_io( .serial_strobe_out(serial_strobe_from_mfp), .serial_data_out(serial_data_from_mfp), .serial_data_out_available(serial_data_from_mfp_available), + .serial_strobe_in(serial_strobe_to_mfp), + .serial_data_in(serial_data_to_mfp), .CORE_TYPE(8'ha3) // mist core id ); diff --git a/cores/mist/user_io.v b/cores/mist/user_io.v index 37e27ed..bb7b4d7 100644 --- a/cores/mist/user_io.v +++ b/cores/mist/user_io.v @@ -17,10 +17,14 @@ module user_io( // serial data from mfp to io controller output reg serial_strobe_out, input serial_data_out_available, - input [7:0] serial_data_out, + input [7:0] serial_data_out, + + // serial data from io controller to mfp + output reg serial_strobe_in, + output reg [7:0] serial_data_in, - output [1:0] BUTTONS, - output [1:0] SWITCHES + output [1:0] BUTTONS, + output [1:0] SWITCHES ); reg toggle; @@ -82,6 +86,7 @@ module user_io( if(cnt == 9) begin ikbd_strobe_in <= 1'b0; ikbd_strobe_out <= 1'b0; + serial_strobe_in <= 1'b0; serial_strobe_out <= 1'b0; end @@ -92,12 +97,18 @@ module user_io( but_sw[0] <= SPI_MOSI; end + // send ikbd byte to acia if(cmd == 2) begin - ikbd_data_in[7:1] <= sbuf; - ikbd_data_in[0] <= SPI_MOSI; + ikbd_data_in <= { sbuf, SPI_MOSI }; ikbd_strobe_in <= 1'b1; end - + + // send serial byte to mfp + if(cmd == 4) begin + serial_data_in <= { sbuf, SPI_MOSI }; + serial_strobe_in <= 1'b1; + end + // give strobe after second ikbd byte (toggle ==1) if((cmd == 3) && toggle) ikbd_strobe_out <= 1'b1;