Created
February 8, 2020 20:18
-
-
Save agrif/3283fd1c1822e40c39eaa3780825780b to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| module tv80_avalon_master(/*AUTOARG*/); | |
| parameter width = 16; | |
| // clock and reset | |
| input clk; | |
| input reset_n; | |
| // avalon master signals | |
| output [width-1:0] address; | |
| output reg read_n; | |
| input [7:0] readdata; | |
| output reg write_n; | |
| output [7:0] writedata; | |
| input waitrequest_n; | |
| // z80 memory signals | |
| output wait_n; | |
| input mreq_n; | |
| input rd_n; | |
| input wr_n; | |
| input [15:0] A; | |
| output [7:0] di; | |
| output di_valid_n; | |
| input [7:0] dout; | |
| reg last_rd_n, last_wr_n; | |
| reg [7:0] readdata_stored; | |
| always @(posedge clk or negedge reset_n) begin | |
| // using the tv80n lets us use wait, but... | |
| // avalon expects only positive edge changes. So. | |
| if (~reset_n) begin | |
| last_rd_n <= 1; | |
| last_wr_n <= 1; | |
| end else begin | |
| last_rd_n <= rd_n; | |
| last_wr_n <= wr_n; | |
| end | |
| // we also need to ensure that we stop reading/writing | |
| // exactly one clock cycle after waitrequest_n goes high | |
| // (to avoid redudant operations, when memory has side effects) | |
| // reads need a register, as z80 IO reads are Very Slow | |
| if (~reset_n) begin | |
| read_n <= 1; | |
| write_n <= 1; | |
| readdata_stored <= 0; | |
| end else begin | |
| if (last_rd_n && ~(mreq_n || rd_n)) begin | |
| read_n <= 0; | |
| end else if (last_wr_n && ~(mreq_n || wr_n)) begin | |
| write_n <= 0; | |
| end else if (waitrequest_n) begin | |
| if (~read_n) | |
| readdata_stored <= readdata; | |
| read_n <= 1; | |
| write_n <= 1; | |
| end | |
| end | |
| end | |
| // just do the dumbest possible things | |
| assign address = A[width-1:0]; | |
| assign di = read_n ? readdata_stored : readdata; | |
| assign di_valid_n = mreq_n || rd_n; | |
| assign writedata = dout; | |
| assign wait_n = waitrequest_n; | |
| endmodule | |
| module tv80_avalon_interrupt(/*AUTOARG*/); | |
| parameter num_interrupts; | |
| parameter interrupt_mode; | |
| input clk; | |
| input reset_n; | |
| input [num_interrupts-1:0] irq; | |
| input nmi_irq; | |
| input m1_n; | |
| input iorq_n; | |
| output int_n; | |
| output nmi_n; | |
| output reg [7:0] di; | |
| output di_valid_n; | |
| assign int_n = ~(|irq); | |
| assign nmi_n = ~nmi_irq; | |
| assign di_valid_n = m1_n | iorq_n; | |
| integer i; | |
| always @(/*AUTOSENSE*/) begin | |
| di <= 0; | |
| for (i = num_interrupts; i > 0; i = i - 1) begin | |
| if (irq[i-1]) begin | |
| if (interrupt_mode == 0) | |
| di <= 'b11000111 | (((i-1) & 'b111) << 3); // RST 0x8 * ((i-1) % 8) | |
| else | |
| di <= (i-1); | |
| end | |
| end | |
| end | |
| endmodule | |
| module qsys_tv80(/*AUTOARG*/); | |
| parameter cpu_variant = 0; | |
| parameter io_width = 8; | |
| parameter fast_io = 0; | |
| parameter num_interrupts = 8; | |
| parameter interrupt_mode = 0; | |
| // clock, reset, and irq | |
| input clk; | |
| input reset_n; | |
| input [num_interrupts-1:0] irq; | |
| input nmi_irq; | |
| // memory master | |
| output [15:0] mem_address; | |
| output mem_read_n; | |
| input [7:0] mem_readdata; | |
| output mem_write_n; | |
| output [7:0] mem_writedata; | |
| input mem_waitrequest_n; | |
| // IO master | |
| output [io_width-1:0] io_address; | |
| output io_read_n; | |
| input [7:0] io_readdata; | |
| output io_write_n; | |
| output [7:0] io_writedata; | |
| input io_waitrequest_n; | |
| // internal signals from avalon converters | |
| wire mem_wait_n, io_wait_n; | |
| wire mem_di_valid_n, io_di_valid_n, int_di_valid_n; | |
| wire [7:0] mem_di; | |
| wire [7:0] io_di; | |
| wire [7:0] int_di; | |
| // connections to cpu, directly | |
| wire wait_n; | |
| wire int_n, nmi_n; | |
| wire m1_n, mreq_n, iorq_n, rd_n, wr_n; | |
| wire [15:0] A; | |
| wire [7:0] di; | |
| wire [7:0] dout; | |
| // our avalon master converters | |
| tv80_avalon_master av_mem(.address(mem_address), | |
| .read_n(mem_read_n), | |
| .readdata(mem_readdata), | |
| .write_n(mem_write_n), | |
| .writedata(mem_writedata), | |
| .waitrequest_n(mem_waitrequest_n), | |
| .wait_n(mem_wait_n), | |
| .mreq_n(mreq_n), | |
| .di(mem_di), | |
| .di_valid_n(mem_di_valid_n), | |
| /*AUTOINST*/); | |
| tv80_avalon_master #(.width(io_width)) | |
| av_io (.address(io_address), | |
| .read_n(io_read_n), | |
| .readdata(io_readdata), | |
| .write_n(io_write_n), | |
| .writedata(io_writedata), | |
| .waitrequest_n(io_waitrequest_n), | |
| .wait_n(io_wait_n), | |
| .mreq_n(iorq_n), | |
| .di(io_di), | |
| .di_valid_n(io_di_valid_n), | |
| /*AUTOINST*/); | |
| tv80_avalon_interrupt #(/*AUTOINSTPARAM*/) | |
| av_int (.di(int_di), | |
| .di_valid_n(int_di_valid_n), | |
| /*AUTOINST*/); | |
| // final wiring assignments to cpu | |
| assign wait_n = ~io_di_valid_n ? io_wait_n : (~mem_di_valid_n ? mem_wait_n : 1); | |
| assign di = ~int_di_valid_n ? int_di : (~io_di_valid_n ? io_di : mem_di); | |
| // we need early write so that our pos/negedge delay doesn't screw us up | |
| tv80n #(.T2Write(1), | |
| .IOWait(fast_io ? 0 : 1), | |
| .Mode(cpu_variant)) | |
| cpu (.reset_n(reset_n), | |
| .clk(clk), | |
| .wait_n(wait_n), | |
| .int_n(int_n), | |
| .nmi_n(nmi_n), | |
| .busrq_n(1), | |
| .m1_n(m1_n), | |
| .mreq_n(mreq_n), | |
| .iorq_n(iorq_n), | |
| .rd_n(rd_n), | |
| .wr_n(wr_n), | |
| //.rfsh_n(...), | |
| //.halt_n(...), | |
| //.busak_n(...), | |
| .A(A), | |
| .di(di), | |
| .dout(dout)); | |
| endmodule |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment