Skip to content

Instantly share code, notes, and snippets.

@agrif
Created February 8, 2020 20:18
Show Gist options
  • Select an option

  • Save agrif/3283fd1c1822e40c39eaa3780825780b to your computer and use it in GitHub Desktop.

Select an option

Save agrif/3283fd1c1822e40c39eaa3780825780b to your computer and use it in GitHub Desktop.
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