From: Joshua Wise <joshua@rebirth.joshuawise.com>
Date: Tue, 6 May 2008 10:29:22 +0000 (-0400)
Subject: Peripherals now have internal latches.
X-Git-Url: http://git.joshuawise.com/fpgaboy.git/commitdiff_plain/a8f4468d0cd6910eba8031e21038d76857a2c107?ds=sidebyside;hp=74610a872e3bead82589e6ea786e928f319540e4

Peripherals now have internal latches.
---

diff --git a/Interrupt.v b/Interrupt.v
index fcc396b..2686146 100644
--- a/Interrupt.v
+++ b/Interrupt.v
@@ -19,10 +19,13 @@ module Interrupt(
 	reg [7:0] imask = 16'hFFFF;
 	reg [7:0] ihold = 8'b0;
 	wire [7:0] imasked = ihold & imask;
+	
+	reg rdlatch = 0;
+	reg [15:0] addrlatch = 0;
 
-	assign data = rd ?
-	                 (addr == `ADDR_IF) ? ihold :
-	                 (addr == `ADDR_IE) ? imask :
+	assign data = rdlatch ?
+	                 (addrlatch == `ADDR_IF) ? ihold :
+	                 (addrlatch == `ADDR_IE) ? imask :
 	                 8'bzzzzzzzz :
 		      8'bzzzzzzzz;
 
@@ -45,6 +48,8 @@ module Interrupt(
 		end
 		else
 			ihold <= ihold | iflag;
+		rdlatch <= rd;
+		addrlatch <= addr;
 	end
 
 endmodule
diff --git a/LCDC.v b/LCDC.v
index a198c45..add6893 100644
--- a/LCDC.v
+++ b/LCDC.v
@@ -21,6 +21,10 @@ module LCDC(
 	output wire lcdclk, lcdvs, lcdhs,
 	output reg [2:0] lcdr, lcdg, output reg [1:0] lcdb);
 	
+	/***** Bus latches *****/
+	reg rdlatch = 0;
+	reg [15:0] addrlatch = 0;
+	
 	/***** Needed prototypes *****/
 	wire [1:0] pixdata;
 	
@@ -172,26 +176,28 @@ module LCDC(
 	end
   
 	/***** Bus interface *****/
-	assign data = rd ?
-			((addr == `ADDR_LCDC) ? rLCDC :
-			 (addr == `ADDR_STAT) ? {rSTAT[7:3], (rLYC == posy) ? 1'b1 : 1'b0, mode} :
-			 (addr == `ADDR_SCY) ? rSCY :
-			 (addr == `ADDR_SCX) ? rSCX :
-			 (addr == `ADDR_LY) ? posy :
-			 (addr == `ADDR_LYC) ? rLYC :
-			 (addr == `ADDR_BGP) ? rBGP :
-			 (addr == `ADDR_OBP0) ? rOBP0 :
-			 (addr == `ADDR_OBP1) ? rOBP1 :
-			 (addr == `ADDR_WY) ? rWY :
-			 (addr == `ADDR_WX) ? rWX :
-			 (decode_tiledata && addr[0]) ? tilehigh :
-			 (decode_tiledata && ~addr[0]) ? tilelow :
+	assign data = rdlatch ?
+			((addrlatch == `ADDR_LCDC) ? rLCDC :
+			 (addrlatch == `ADDR_STAT) ? {rSTAT[7:3], (rLYC == posy) ? 1'b1 : 1'b0, mode} :
+			 (addrlatch == `ADDR_SCY) ? rSCY :
+			 (addrlatch == `ADDR_SCX) ? rSCX :
+			 (addrlatch == `ADDR_LY) ? posy :
+			 (addrlatch == `ADDR_LYC) ? rLYC :
+			 (addrlatch == `ADDR_BGP) ? rBGP :
+			 (addrlatch == `ADDR_OBP0) ? rOBP0 :
+			 (addrlatch == `ADDR_OBP1) ? rOBP1 :
+			 (addrlatch == `ADDR_WY) ? rWY :
+			 (addrlatch == `ADDR_WX) ? rWX :
+			 (decode_tiledata && addrlatch[0]) ? tilehigh :
+			 (decode_tiledata && ~addrlatch[0]) ? tilelow :
 			 (decode_bgmap1) ? tileno :
 			 8'bzzzzzzzz) :
 		8'bzzzzzzzz;
   
 	always @(posedge clk)
 	begin
+		rdlatch <= rd;
+		addrlatch <= addr;
 		if (wr)
 			case (addr)
 			`ADDR_LCDC:	rLCDC <= data;
diff --git a/Sound1.v b/Sound1.v
index 21b1dec..ca97b17 100644
--- a/Sound1.v
+++ b/Sound1.v
@@ -23,18 +23,23 @@ module Sound1(
 	reg [3:0] delta = 4'b1111;
 	reg toggle = 0;
 	reg [3:0] snd_out = 0;
+	
+	reg rdlatch;
+	reg [15:0] addrlatch;
 
 	assign snd_data = en ? snd_out : 0;
 
-	assign data = rd ?
-	                 addr == `ADDR_NR10 ? nr10 :
-	                 addr == `ADDR_NR11 ? nr11 :
-	                 addr == `ADDR_NR12 ? nr12 :
-	                 addr == `ADDR_NR13 ? nr13 :
-	                 addr == `ADDR_NR14 ? nr14 : 8'bzzzzzzzz
+	assign data = rdlatch ?
+	                 addrlatch == `ADDR_NR10 ? nr10 :
+	                 addrlatch == `ADDR_NR11 ? nr11 :
+	                 addrlatch == `ADDR_NR12 ? nr12 :
+	                 addrlatch == `ADDR_NR13 ? nr13 :
+	                 addrlatch == `ADDR_NR14 ? nr14 : 8'bzzzzzzzz
 	              : 8'bzzzzzzzz;
 
 	always @ (posedge core_clk) begin
+		rdlatch <= rd;
+		addrlatch <= addr;
 		if(en && wr) begin
 			case(addr)
 			`ADDR_NR10: nr10 <= data;
diff --git a/Sound2.v b/Sound2.v
index cf8e83a..ef38263 100644
--- a/Sound2.v
+++ b/Sound2.v
@@ -24,15 +24,20 @@ module Sound2(
 	reg [3:0] snd_out = 0;
 
 	assign snd_data = en ? snd_out : 0;
+	
+	reg rdlatch;
+	reg [15:0] addrlatch;
 
-	assign data = rd ?
-	                 addr == `ADDR_NR21 ? nr21 :
-	                 addr == `ADDR_NR22 ? nr22 :
-	                 addr == `ADDR_NR23 ? nr23 :
-	                 addr == `ADDR_NR24 ? nr24 : 8'bzzzzzzzz
+	assign data = rdlatch ?
+	                 addrlatch == `ADDR_NR21 ? nr21 :
+	                 addrlatch == `ADDR_NR22 ? nr22 :
+	                 addrlatch == `ADDR_NR23 ? nr23 :
+	                 addrlatch == `ADDR_NR24 ? nr24 : 8'bzzzzzzzz
 	              : 8'bzzzzzzzz;
 
 	always @ (posedge core_clk) begin
+		rdlatch <= rd;
+		addrlatch <= addr;
 		if(en && wr) begin
 			case(addr)
 			`ADDR_NR21: nr21 <= data;
diff --git a/Soundcore.v b/Soundcore.v
index 626001d..70c4db1 100644
--- a/Soundcore.v
+++ b/Soundcore.v
@@ -29,14 +29,19 @@ module Soundcore(
 		(nr51[7] ? sndout4 : 4'b0);
 	assign sndout3 = 0;
 	assign sndout4 = 0;
-
-	assign data = rd ?
-	                 addr == `ADDR_NR50 ? nr50 :
-	                 addr == `ADDR_NR51 ? nr51 :
-	                 addr == `ADDR_NR52 ? nr52 : 8'bzzzzzzzz
+	
+	reg rdlatch;
+	reg [15:0] addrlatch;
+	
+	assign data = rdlatch ?
+	                 addrlatch == `ADDR_NR50 ? nr50 :
+	                 addrlatch == `ADDR_NR51 ? nr51 :
+	                 addrlatch == `ADDR_NR52 ? nr52 : 8'bzzzzzzzz
 		      : 8'bzzzzzzzz;
 
 	always @ (posedge core_clk) begin
+		rdlatch <= rd;
+		addrlatch <= addr;
 		if(wr) begin
 			case(addr)
 			`ADDR_NR50: nr50 <= data;
diff --git a/System.v b/System.v
index 4d0ddbb..ebc9be4 100644
--- a/System.v
+++ b/System.v
@@ -6,6 +6,7 @@ module ROM(
 	input clk,
 	input wr, rd);
 
+	reg rdlatch = 0;
 	reg [7:0] odata;
 
 	// synthesis attribute ram_style of rom is block
@@ -13,9 +14,11 @@ module ROM(
 	initial $readmemh("rom.hex", rom);
 
 	wire decode = address[15:13] == 0;
-	always @(posedge clk)
+	always @(posedge clk) begin
+		rdlatch <= rd && decode;
 		odata <= rom[address[10:0]];
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	end
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 endmodule
 
 module BootstrapROM(
@@ -24,12 +27,15 @@ module BootstrapROM(
 	input clk,
 	input wr, rd);
 
+	reg rdlatch = 0;
 	reg [7:0] brom [255:0];
 	initial $readmemh("bootstrap.hex", brom);
 
 	wire decode = address[15:8] == 0;
 	wire [7:0] odata = brom[address[7:0]];
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	always @(posedge clk)
+		rdlatch <= rd && decode;
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 endmodule
 
 module MiniRAM(
@@ -41,13 +47,15 @@ module MiniRAM(
 	reg [7:0] ram [127:0];
 	
 	wire decode = (address >= 16'hFF80) && (address <= 16'hFFFE);
+	reg rdlatch = 0;
 	reg [7:0] odata;
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 	
 	always @(posedge clk)
 	begin
-		if (decode)	// This has to go this way. The only way XST knows how to do
-		begin				// block ram is chip select, write enable, and always
+		rdlatch <= rd && decode;
+		if (decode)		// This has to go this way. The only way XST knows how to do
+		begin			// block ram is chip select, write enable, and always
 			if (wr)		// reading. "else if rd" does not cut it ...
 				ram[address[6:0]] <= data;
 			odata <= ram[address[6:0]];
@@ -69,6 +77,10 @@ module CellularRAM(
 	parameter ADDR_PROGADDRL = 16'hFF62;
 	parameter ADDR_PROGDATA = 16'hFF63;
 	
+	reg rdlatch = 0, wrlatch = 0;
+	reg [15:0] addrlatch = 0;
+	reg [7:0] datalatch = 0;
+	
 	reg [7:0] progaddrh, progaddrm, progaddrl;
 	
 	assign cr_nADV = 0;	/* Addresses are always valid! :D */
@@ -78,30 +90,35 @@ module CellularRAM(
 	assign cr_CRE = 0;	/* Data writes, not config */
 	assign cr_CLK = 0;	/* Clock? I think not! */
 	
-	wire decode = (address[15:14] == 2'b00) /* extrom */ || (address[15:13] == 3'b101) /* extram */ || (address == ADDR_PROGDATA);
+	wire decode = (addrlatch[15:14] == 2'b00) /* extrom */ || (addrlatch[15:13] == 3'b101) /* extram */ || (addrlatch == ADDR_PROGDATA);
 	
-	assign cr_nOE = decode ? ~rd : 1;
-	assign cr_nWE = decode ? ~wr : 1;
+	assign cr_nOE = decode ? ~rdlatch : 1;
+	assign cr_nWE = decode ? ~wrlatch : 1;
 	
-	assign cr_DQ = (~cr_nOE) ? 16'bzzzzzzzzzzzzzzzz : {8'b0, data};
-	assign cr_A = (address[15:14] == 2'b00) ? /* extrom */ {9'b0,address[13:0]} :
-			(address[15:13] == 3'b101) ? {1'b1, 9'b0, address[12:0]} :
-			(address == ADDR_PROGDATA) ? {progaddrh[6:0], progaddrm[7:0], progaddrl[7:0]} :
+	assign cr_DQ = (~cr_nOE) ? 16'bzzzzzzzzzzzzzzzz : {8'b0, datalatch};
+	assign cr_A = (addrlatch[15:14] == 2'b00) ? /* extrom */ {9'b0,addrlatch[13:0]} :
+			(addrlatch[15:13] == 3'b101) ? {1'b1, 9'b0, addrlatch[12:0]} :
+			(addrlatch == ADDR_PROGDATA) ? {progaddrh[6:0], progaddrm[7:0], progaddrl[7:0]} :
 			23'b0;
 	
 	reg [7:0] regbuf;
 	
-	always @(posedge clk)
+	always @(posedge clk) begin
 		case (address)
 		ADDR_PROGADDRH: if (wr) progaddrh <= data;
 		ADDR_PROGADDRM: if (wr) progaddrm <= data;
 		ADDR_PROGADDRL: if (wr) progaddrl <= data;
 		endcase
+		rdlatch <= rd;
+		wrlatch <= wr;
+		addrlatch <= address;
+		datalatch <= data;
+	end
 	
-	assign data = (rd && decode) ?
-				(address == ADDR_PROGADDRH) ? progaddrh :
-				(address == ADDR_PROGADDRM) ? progaddrm :
-				(address == ADDR_PROGADDRL) ? progaddrl :
+	assign data = (rdlatch && decode) ?
+				(addrlatch == ADDR_PROGADDRH) ? progaddrh :
+				(addrlatch == ADDR_PROGADDRM) ? progaddrm :
+				(addrlatch == ADDR_PROGADDRL) ? progaddrl :
 				cr_DQ
 			: 8'bzzzzzzzz;
 endmodule
@@ -117,10 +134,12 @@ module InternalRAM(
 	
 	wire decode = (address >= 16'hC000) && (address <= 16'hFDFF);	/* This includes echo RAM. */
 	reg [7:0] odata;
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	reg rdlatch = 0;
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 	
 	always @(posedge clk)
 	begin
+		rdlatch <= rd && decode;
 		if (decode)		// This has to go this way. The only way XST knows how to do
 		begin			// block ram is chip select, write enable, and always
 			if (wr)		// reading. "else if rd" does not cut it ...
@@ -140,10 +159,12 @@ module Switches(
 	
 	wire decode = address == 16'hFF51;
 	reg [7:0] odata;
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	reg rdlatch = 0;
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 	
 	always @(posedge clk)
 	begin
+		rdlatch <= rd && decode;
 		if (decode && rd)
 			odata <= switches;
 		else if (decode && wr)
diff --git a/Timer.v b/Timer.v
index e46b38b..facf20f 100644
--- a/Timer.v
+++ b/Timer.v
@@ -11,15 +11,17 @@ module Timer(
 	inout [7:0] data,
 	output reg irq = 0);
 
+	reg rdlatch = 0;
+	reg [15:0] addrlatch = 0;
 	reg [7:0] tima = 0, tma = 0, tac = 0, div = 0;
 	reg ovf = 0;
 	reg [9:0] clkdv = 0;
 
-	wire is_tima = addr == `ADDR_TIMA;
-	wire is_tma  = addr == `ADDR_TMA;
-	wire is_tac  = addr == `ADDR_TAC;
+	wire is_tima = addrlatch == `ADDR_TIMA;
+	wire is_tma  = addrlatch == `ADDR_TMA;
+	wire is_tac  = addrlatch == `ADDR_TAC;
 
-	assign data = rd ?
+	assign data = rdlatch ?
 	                 is_tima ? tima :
 	                 is_tma ? tma :
 	                 is_tac ? tac :
@@ -35,6 +37,9 @@ module Timer(
 
 	always @ (posedge clk) 
 	begin
+		rdlatch <= rd;
+		addrlatch <= addr;
+		
 		if(wr) begin
 			case(addr)
 			`ADDR_DIV: div <= 8'b0;
diff --git a/Uart.v b/Uart.v
index f9d71f4..07f996a 100644
--- a/Uart.v
+++ b/Uart.v
@@ -10,11 +10,12 @@ module UART(
 	input [15:0] addr,
 	inout [7:0] data,
 	output reg serial = 1);
-	
+
+	reg rdlatch = 0;
 	wire decode = (addr == `MMAP_ADDR);
 	
 	wire [7:0] odata;
-	assign data = (rd && decode) ? odata : 8'bzzzzzzzz;
+	assign data = rdlatch ? odata : 8'bzzzzzzzz;
 
 	reg [7:0] data_stor = 0;
 	reg [15:0] clkdiv = 0;
@@ -27,6 +28,7 @@ module UART(
 
 	always @ (posedge clk)
 	begin
+		rdlatch <= rd && decode;
 		/* deal with diqing */
 		if(newdata) begin
 			data_stor <= data;