├── fpga_version ├── ula_test_for_ise_and_isim │ ├── ram64bytes.v │ ├── test_ula.v │ ├── test_ulaplus.v │ ├── cpu.v │ ├── isim_test_for_ula.gise │ ├── signalview.wcfg │ ├── ula.v │ ├── signalview_ulaplus.wcfg │ ├── ula_with_timex_hicolor_support_and_ulaplus.v │ └── isim_test_for_ula.xise ├── testbench │ └── test_ula.v └── rtl │ ├── ula.v │ ├── ula_with_timex_hicolor_support.v │ └── ula_with_timex_hicolor_support_and_ulaplus.v └── cpld_version └── rtl └── ula.v /fpga_version/ula_test_for_ise_and_isim/ram64bytes.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 20:57:11 04/29/2012 7 | // Design Name: 8 | // Module Name: ram64bytes 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | module ram64bytes( 22 | input clk, 23 | input [5:0] a, 24 | input [7:0] din, 25 | output [7:0] dout, 26 | input we 27 | ); 28 | 29 | reg [7:0] mem[0:63]; 30 | assign dout = mem[a]; //non registered address. Ugly, but works :( 31 | 32 | integer i; 33 | initial begin 34 | for (i=0;i<=63;i=i+1) 35 | mem[i] = i/8; 36 | end 37 | 38 | always @(posedge clk) begin 39 | if (we) 40 | mem[a] <= din; 41 | end 42 | endmodule 43 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/test_ula.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 20:16:22 04/08/2012 8 | // Design Name: ula 9 | // Module Name: C:/proyectos_xilinx/ulaplus/test_reference_ula.v 10 | // Project Name: ulaplus 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: ula 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module test_standard_ula; 26 | 27 | // Inputs 28 | reg clk14; 29 | wire [15:0] a; 30 | wire [7:0] din; 31 | wire mreq_n; 32 | wire iorq_n; 33 | wire wr_n; 34 | wire rfsh_n; 35 | reg [7:0] vramdout; 36 | reg ear; 37 | reg [4:0] kbcolumns; 38 | 39 | // Outputs 40 | wire [7:0] dout; 41 | wire clkcpu; 42 | wire msk_int_n; 43 | wire [13:0] va; 44 | wire [7:0] vramdin; 45 | wire vramoe; 46 | wire vramcs; 47 | wire vramwe; 48 | wire mic; 49 | wire spk; 50 | wire [7:0] kbrows; 51 | wire r; 52 | wire g; 53 | wire b; 54 | wire i; 55 | wire csync; 56 | 57 | // Instantiate the Unit Under Test (UUT) 58 | ula uut ( 59 | .clk14(clk14), 60 | .a(a), 61 | .din(din), 62 | .dout(dout), 63 | .mreq_n(mreq_n), 64 | .iorq_n(iorq_n), 65 | .rd_n(1'b1), 66 | .wr_n(wr_n), 67 | .rfsh_n(rfsh_n), 68 | .clkcpu(clkcpu), 69 | .msk_int_n(msk_int_n), 70 | .va(va), 71 | .vramdout(vramdout), 72 | .vramdin(vramdin), 73 | .vramoe(vramoe), 74 | .vramcs(vramcs), 75 | .vramwe(vramwe), 76 | .ear(ear), 77 | .mic(mic), 78 | .spk(spk), 79 | .kbrows(kbrows), 80 | .kbcolumns(kbcolumns), 81 | .r(r), 82 | .g(g), 83 | .b(b), 84 | .i(i), 85 | .csync(csync) 86 | ); 87 | 88 | z80memio cpu ( 89 | .clk(clkcpu), 90 | .a(a), 91 | .d(din), 92 | .mreq_n(mreq_n), 93 | .iorq_n(iorq_n), 94 | .wr_n(wr_n), 95 | .rfsh_n(rfsh_n) 96 | ); 97 | 98 | initial begin 99 | // Initialize Inputs 100 | clk14 = 0; 101 | vramdout = 8'b01010101; 102 | ear = 0; 103 | kbcolumns = 0; 104 | end 105 | 106 | always begin 107 | clk14 = #35.714286 ~clk14; 108 | end 109 | endmodule 110 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/test_ulaplus.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 20:16:22 04/08/2012 8 | // Design Name: ula 9 | // Module Name: C:/proyectos_xilinx/ulaplus/test_reference_ula.v 10 | // Project Name: ulaplus 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: ula 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module test_ulaplus; 26 | 27 | // Inputs 28 | reg clk14; 29 | reg reset; 30 | wire [15:0] a; 31 | wire [7:0] din; 32 | wire mreq_n; 33 | wire iorq_n; 34 | wire wr_n; 35 | wire rfsh_n; 36 | reg [7:0] vramdout; 37 | reg ear; 38 | reg [4:0] kbcolumns; 39 | 40 | // Outputs 41 | wire [7:0] dout; 42 | wire clkcpu; 43 | wire msk_int_n; 44 | wire [13:0] va; 45 | wire [7:0] vramdin; 46 | wire vramoe; 47 | wire vramcs; 48 | wire vramwe; 49 | wire mic; 50 | wire spk; 51 | wire [7:0] kbrows; 52 | wire r; 53 | wire g; 54 | wire b; 55 | wire i; 56 | wire [7:0] rgbulaplus; 57 | wire ulaplus_enabled; 58 | wire csync; 59 | 60 | // Instantiate the Unit Under Test (UUT) 61 | ulaplus uut ( 62 | .clk14(clk14), 63 | .reset(reset), 64 | .a(a), 65 | .din(din), 66 | .dout(dout), 67 | .mreq_n(mreq_n), 68 | .iorq_n(iorq_n), 69 | .rd_n(1'b1), 70 | .wr_n(wr_n), 71 | .rfsh_n(rfsh_n), 72 | .clkcpu(clkcpu), 73 | .msk_int_n(msk_int_n), 74 | .va(va), 75 | .vramdout(vramdout), 76 | .vramdin(vramdin), 77 | .vramoe(vramoe), 78 | .vramcs(vramcs), 79 | .vramwe(vramwe), 80 | .ear(ear), 81 | .mic(mic), 82 | .spk(spk), 83 | .kbrows(kbrows), 84 | .kbcolumns(kbcolumns), 85 | .r(r), 86 | .g(g), 87 | .b(b), 88 | .i(i), 89 | .rgbulaplus(rgbulaplus), 90 | .ulaplus_enabled(ulaplus_enabled), 91 | .csync(csync) 92 | ); 93 | 94 | z80memio cpu ( 95 | .clk(clkcpu), 96 | .a(a), 97 | .d(din), 98 | .mreq_n(mreq_n), 99 | .iorq_n(iorq_n), 100 | .wr_n(wr_n), 101 | .rfsh_n(rfsh_n) 102 | ); 103 | 104 | initial begin 105 | // Initialize Inputs 106 | clk14 = 0; 107 | vramdout = 8'b01010101; 108 | ear = 0; 109 | kbcolumns = 0; 110 | reset = 1; 111 | reset = #20 0; 112 | end 113 | 114 | always begin 115 | clk14 = #35.714286 ~clk14; 116 | end 117 | 118 | endmodule 119 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/cpu.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: 4 | // Engineer: 5 | // 6 | // Create Date: 16:50:27 05/02/2012 7 | // Design Name: 8 | // Module Name: cpu 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | module z80memr ( 23 | input clk, 24 | output [15:0] a, 25 | output [7:0] d, 26 | output mreq, 27 | output rd 28 | ); 29 | 30 | reg rmreq = 1; 31 | reg rrd = 1; 32 | assign mreq = rmreq; 33 | assign rd = rrd; 34 | reg [1:0] estado = 2; 35 | assign d = 8'bzzzzzzzz; 36 | 37 | reg [15:0] ra = 16'h7FFF; 38 | assign a = ra; 39 | 40 | always @(posedge clk) begin 41 | if (estado==2) begin 42 | estado <= 0; 43 | ra <= ~ra; 44 | end 45 | else 46 | estado <= estado + 1; 47 | end 48 | 49 | always @(*) begin 50 | if (estado==0 && clk) 51 | {rmreq,rrd} = 2'b11; 52 | else if (estado==0 && !clk) 53 | {rmreq,rrd} = 2'b00; 54 | else if (estado==1) 55 | {rmreq,rrd} = 2'b00; 56 | else if (estado==2 && clk) 57 | {rmreq,rrd} = 2'b00; 58 | else 59 | {rmreq,rrd} = 2'b11; 60 | end 61 | endmodule 62 | 63 | 64 | module z80memio ( 65 | input clk, 66 | output [15:0] a, 67 | output [7:0] d, 68 | output mreq_n, 69 | output iorq_n, 70 | output wr_n, 71 | output rfsh_n 72 | ); 73 | 74 | reg rmreq = 1; 75 | reg riorq = 1; 76 | reg rwr = 1; 77 | reg rrfsh = 1; 78 | assign mreq_n = rmreq; 79 | assign iorq_n = riorq; 80 | assign wr_n = rwr; 81 | assign rfsh_n = rrfsh; 82 | 83 | reg [1:0] estado = 0; 84 | 85 | reg [5:0] memioseq = 6'b011001; 86 | reg [5:0] io2seq = 5'b011000; 87 | reg [4:0] hiloseq = 5'b01010; 88 | wire memio = memioseq[0]; // 0 = mem, 1 = io 89 | wire hilo = hiloseq[0]; // 0 = access to lower RAM/Port FEh 90 | wire iohi = io2seq[0]; // 0 = port 00FF/00FE, 1 = port 40FE,40FF 91 | 92 | 93 | reg [15:0] ra; 94 | assign a = ra; 95 | 96 | reg [7:0] rd; 97 | assign d = rd; 98 | 99 | reg [7:0] iodata = 0; 100 | reg [7:0] memdata = 0; 101 | reg [15:0] memaddr = 16384; 102 | 103 | always @(posedge clk) begin 104 | if (estado==2 && !memio) begin 105 | estado <= 0; 106 | memioseq <= { memioseq[0], memioseq[5:1] }; 107 | hiloseq <= { hiloseq[0], hiloseq[4:1] }; 108 | io2seq <= { io2seq[0], io2seq[5:1] }; 109 | memdata <= memdata + 1; 110 | if (memaddr == 23295) 111 | memaddr <= 16384; 112 | else 113 | memaddr <= memaddr + 1; 114 | end 115 | else if (estado==3 && memio) begin 116 | estado <= 0; 117 | memioseq <= { memioseq[0], memioseq[5:1] }; 118 | hiloseq <= { hiloseq[0], hiloseq[4:1] }; 119 | io2seq <= { io2seq[0], io2seq[5:1] }; 120 | iodata <= iodata + 1; 121 | end 122 | else 123 | estado <= estado + 1; 124 | end 125 | 126 | always @(*) begin 127 | if (memio) begin // if this is an I/O bus cycle... 128 | case ({estado,clk}) 129 | 3'b001 : begin 130 | {rmreq,riorq,rwr} = 3'b111; 131 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 132 | rd = 8'bzzzzzzzz; 133 | end 134 | 3'b000 : begin 135 | {rmreq,riorq,rwr} = 3'b111; 136 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 137 | rd = iodata; 138 | end 139 | 3'b011,3'b010,3'b101,3'b100,3'b111 : 140 | begin 141 | {rmreq,riorq,rwr} = 3'b100; 142 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 143 | rd = iodata; 144 | end 145 | 3'b110 : begin 146 | {rmreq,riorq,rwr} = 3'b111; 147 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 148 | rd = iodata; 149 | end 150 | endcase 151 | end 152 | else begin // this is a MEM bus cycle 153 | case ({estado,clk}) 154 | 3'b001 : begin 155 | {rmreq,riorq,rwr} = 3'b111; 156 | ra = {hilo,memaddr[14:0]}; 157 | rd = 8'bzzzzzzzz; 158 | end 159 | 3'b000,3'b011 : 160 | begin 161 | {rmreq,riorq,rwr} = 3'b011; 162 | ra = {hilo,memaddr[14:0]}; 163 | rd = memdata; 164 | end 165 | 3'b010,3'b101 : 166 | begin 167 | {rmreq,riorq,rwr} = 3'b010; 168 | ra = {hilo,memaddr[14:0]}; 169 | rd = memdata; 170 | end 171 | 3'b100 : begin 172 | {rmreq,riorq,rwr} = 3'b111; 173 | ra = {hilo,memaddr[14:0]}; 174 | rd = memdata; 175 | end 176 | endcase 177 | end 178 | end 179 | endmodule 180 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/isim_test_for_ula.gise: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 11.1 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /fpga_version/testbench/test_ula.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | 3 | //////////////////////////////////////////////////////////////////////////////// 4 | // Company: 5 | // Engineer: 6 | // 7 | // Create Date: 20:16:22 04/08/2012 8 | // Design Name: ula 9 | // Module Name: C:/proyectos_xilinx/ulaplus/test_reference_ula.v 10 | // Project Name: ulaplus 11 | // Target Device: 12 | // Tool versions: 13 | // Description: 14 | // 15 | // Verilog Test Fixture created by ISE for module: ula 16 | // 17 | // Dependencies: 18 | // 19 | // Revision: 20 | // Revision 0.01 - File Created 21 | // Additional Comments: 22 | // 23 | //////////////////////////////////////////////////////////////////////////////// 24 | 25 | module test_reference_ula; 26 | 27 | // Inputs 28 | reg clk14; 29 | wire [15:0] a; 30 | wire [7:0] din; 31 | wire mreq_n; 32 | wire iorq_n; 33 | wire wr_n; 34 | wire rfsh_n; 35 | reg [7:0] vramdout; 36 | reg ear; 37 | reg [4:0] kbcolumns; 38 | 39 | // Outputs 40 | wire [7:0] dout; 41 | wire clkcpu; 42 | wire msk_int_n; 43 | wire [13:0] va; 44 | wire [7:0] vramdin; 45 | wire vramoe; 46 | wire vramcs; 47 | wire vramwe; 48 | wire mic; 49 | wire spk; 50 | wire [7:0] kbrows; 51 | wire r; 52 | wire g; 53 | wire b; 54 | wire i; 55 | wire csync; 56 | 57 | // Instantiate the Unit Under Test (UUT) 58 | ula uut ( 59 | .clk14(clk14), 60 | .a(a), 61 | .din(din), 62 | .dout(dout), 63 | .mreq_n(mreq_n), 64 | .iorq_n(iorq_n), 65 | .rd_n(1'b1), 66 | .wr_n(wr_n), 67 | .rfsh_n(rfsh_n), 68 | .clkcpu(clkcpu), 69 | .msk_int_n(msk_int_n), 70 | .va(va), 71 | .vramdout(vramdout), 72 | .vramdin(vramdin), 73 | .vramoe(vramoe), 74 | .vramcs(vramcs), 75 | .vramwe(vramwe), 76 | .ear(ear), 77 | .mic(mic), 78 | .spk(spk), 79 | .kbrows(kbrows), 80 | .kbcolumns(kbcolumns), 81 | .r(r), 82 | .g(g), 83 | .b(b), 84 | .i(i), 85 | .csync(csync) 86 | ); 87 | 88 | z80memio cpu ( 89 | .clk(clkcpu), 90 | .a(a), 91 | .d(din), 92 | .mreq_n(mreq_n), 93 | .iorq_n(iorq_n), 94 | .wr_n(wr_n), 95 | .rfsh_n(rfsh_n) 96 | ); 97 | 98 | initial begin 99 | // Initialize Inputs 100 | clk14 = 0; 101 | vramdout = 8'b01010101; 102 | ear = 0; 103 | kbcolumns = 0; 104 | end 105 | 106 | always begin 107 | clk14 = #35.714286 ~clk14; 108 | end 109 | endmodule 110 | 111 | module z80memr ( 112 | input clk, 113 | output [15:0] a, 114 | output [7:0] d, 115 | output mreq, 116 | output rd 117 | ); 118 | 119 | reg rmreq = 1; 120 | reg rrd = 1; 121 | assign mreq = rmreq; 122 | assign rd = rrd; 123 | reg [1:0] estado = 2; 124 | assign d = 8'bzzzzzzzz; 125 | 126 | reg [15:0] ra = 16'h7FFF; 127 | assign a = ra; 128 | 129 | always @(posedge clk) begin 130 | if (estado==2) begin 131 | estado <= 0; 132 | ra <= ~ra; 133 | end 134 | else 135 | estado <= estado + 1; 136 | end 137 | 138 | always @(*) begin 139 | if (estado==0 && clk) 140 | {rmreq,rrd} = 2'b11; 141 | else if (estado==0 && !clk) 142 | {rmreq,rrd} = 2'b00; 143 | else if (estado==1) 144 | {rmreq,rrd} = 2'b00; 145 | else if (estado==2 && clk) 146 | {rmreq,rrd} = 2'b00; 147 | else 148 | {rmreq,rrd} = 2'b11; 149 | end 150 | endmodule 151 | 152 | 153 | module z80memio ( 154 | input clk, 155 | output [15:0] a, 156 | output [7:0] d, 157 | output mreq_n, 158 | output iorq_n, 159 | output wr_n, 160 | output rfsh_n 161 | ); 162 | 163 | reg rmreq = 1; 164 | reg riorq = 1; 165 | reg rwr = 1; 166 | reg rrfsh = 1; 167 | assign mreq_n = rmreq; 168 | assign iorq_n = riorq; 169 | assign wr_n = rwr; 170 | assign rfsh_n = rrfsh; 171 | 172 | reg [1:0] estado = 0; 173 | 174 | reg [5:0] memioseq = 6'b011001; 175 | reg [5:0] io2seq = 5'b011000; 176 | reg [4:0] hiloseq = 5'b01010; 177 | wire memio = memioseq[0]; // 0 = mem, 1 = io 178 | wire hilo = hiloseq[0]; // 0 = access to lower RAM/Port FEh 179 | wire iohi = io2seq[0]; // 0 = port 00FF/00FE, 1 = port 40FE,40FF 180 | 181 | 182 | reg [15:0] ra; 183 | assign a = ra; 184 | 185 | reg [7:0] rd; 186 | assign d = rd; 187 | 188 | reg [7:0] iodata = 0; 189 | reg [7:0] memdata = 0; 190 | reg [15:0] memaddr = 16384; 191 | 192 | always @(posedge clk) begin 193 | if (estado==2 && !memio) begin 194 | estado <= 0; 195 | memioseq <= { memioseq[0], memioseq[5:1] }; 196 | hiloseq <= { hiloseq[0], hiloseq[4:1] }; 197 | io2seq <= { io2seq[0], io2seq[5:1] }; 198 | memdata <= memdata + 1; 199 | if (memaddr == 23295) 200 | memaddr <= 16384; 201 | else 202 | memaddr <= memaddr + 1; 203 | end 204 | else if (estado==3 && memio) begin 205 | estado <= 0; 206 | memioseq <= { memioseq[0], memioseq[5:1] }; 207 | hiloseq <= { hiloseq[0], hiloseq[4:1] }; 208 | io2seq <= { io2seq[0], io2seq[5:1] }; 209 | iodata <= iodata + 1; 210 | end 211 | else 212 | estado <= estado + 1; 213 | end 214 | 215 | always @(*) begin 216 | if (memio) begin // if this is an I/O bus cycle... 217 | case ({estado,clk}) 218 | 3'b001 : begin 219 | {rmreq,riorq,rwr} = 3'b111; 220 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 221 | rd = 8'bzzzzzzzz; 222 | end 223 | 3'b000 : begin 224 | {rmreq,riorq,rwr} = 3'b111; 225 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 226 | rd = iodata; 227 | end 228 | 3'b011,3'b010,3'b101,3'b100,3'b111 : 229 | begin 230 | {rmreq,riorq,rwr} = 3'b100; 231 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 232 | rd = iodata; 233 | end 234 | 3'b110 : begin 235 | {rmreq,riorq,rwr} = 3'b111; 236 | ra = {1'b0, iohi, 13'b0000001111111, hilo}; 237 | rd = iodata; 238 | end 239 | endcase 240 | end 241 | else begin // this is a MEM bus cycle 242 | case ({estado,clk}) 243 | 3'b001 : begin 244 | {rmreq,riorq,rwr} = 3'b111; 245 | ra = {hilo,memaddr[14:0]}; 246 | rd = 8'bzzzzzzzz; 247 | end 248 | 3'b000,3'b011 : 249 | begin 250 | {rmreq,riorq,rwr} = 3'b011; 251 | ra = {hilo,memaddr[14:0]}; 252 | rd = memdata; 253 | end 254 | 3'b010,3'b101 : 255 | begin 256 | {rmreq,riorq,rwr} = 3'b010; 257 | ra = {hilo,memaddr[14:0]}; 258 | rd = memdata; 259 | end 260 | 3'b100 : begin 261 | {rmreq,riorq,rwr} = 3'b111; 262 | ra = {hilo,memaddr[14:0]}; 263 | rd = memdata; 264 | end 265 | endcase 266 | end 267 | end 268 | endmodule 269 | -------------------------------------------------------------------------------- /cpld_version/rtl/ula.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ULA 8 | // Module Name: ula_reference_design 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ula( 26 | input clk14, // 14MHz master clock 27 | // CPU interfacing 28 | input [15:0] a, // Address bus from CPU (not all lines are used) 29 | input [7:0] d, // Data bus from VRAM 30 | input mreq_n, // MREQ from CPU 31 | input ioreq_n, // IORQ+A0 from CPU 32 | output clkcpu, // CLK to CPU 33 | output msk_int_n, // Vertical retrace interrupt, to CPU 34 | // VRAM interfacing 35 | output [13:0] va, // Address bus to VRAM (16K) 36 | output vramoe_n, // 37 | output vramcs_n, // Control signals for VRAM 38 | output vramwe_n, // 39 | // Control signals 40 | output vram_in_use, // ==1 to indicate that VRAM is in use by ULA 41 | input [2:0] BorderColor, // current border colour 42 | // Video output 43 | output r, // 44 | output g, // RGB TTL signal 45 | output b, // with separate bright 46 | output i, // and composite sync 47 | output csync // 48 | ); 49 | 50 | // Pixel clock 51 | reg clk7 = 0; 52 | always @(posedge clk14) 53 | clk7 <= !clk7; 54 | 55 | // Horizontal counter 56 | reg [8:0] hc = 0; 57 | always @(posedge clk7) begin 58 | if (hc==447) 59 | hc <= 0; 60 | else 61 | hc <= hc + 1; 62 | end 63 | 64 | // Vertical counter 65 | reg [8:0] vc = 0; 66 | always @(posedge clk7) begin 67 | if (hc==447) begin 68 | if (vc == 311) 69 | vc <= 0; 70 | else 71 | vc <= vc + 1; 72 | end 73 | end 74 | 75 | // HBlank generation 76 | reg HBlank_n = 1; 77 | always @(negedge clk7) begin 78 | if (`cyclestart(hc,320)) 79 | HBlank_n <= 0; 80 | else if (`cycleend(hc,415)) 81 | HBlank_n <= 1; 82 | end 83 | 84 | // HSync generation (6C ULA version) 85 | reg HSync_n = 1; 86 | always @(negedge clk7) begin 87 | if (`cyclestart(hc,344)) 88 | HSync_n <= 0; 89 | else if (`cycleend(hc,375)) 90 | HSync_n <= 1; 91 | end 92 | 93 | // VBlank generation 94 | reg VBlank_n = 1; 95 | always @(negedge clk7) begin 96 | if (`cyclestart(vc,248)) 97 | VBlank_n <= 0; 98 | else if (`cycleend(vc,255)) 99 | VBlank_n <= 1; 100 | end 101 | 102 | // VSync generation (PAL) 103 | reg VSync_n = 1; 104 | always @(negedge clk7) begin 105 | if (`cyclestart(vc,248)) 106 | VSync_n <= 0; 107 | else if (`cycleend(vc,251)) 108 | VSync_n <= 1; 109 | end 110 | 111 | // INT generation 112 | reg INT_n = 1; 113 | assign msk_int_n = INT_n; 114 | always @(negedge clk7) begin 115 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 116 | INT_n <= 0; 117 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 118 | INT_n <= 1; 119 | end 120 | 121 | // Border control signal (=0 when we're not displaying paper/ink pixels) 122 | reg Border_n = 1; 123 | always @(negedge clk7) begin 124 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 125 | Border_n <= 0; 126 | else 127 | Border_n <= 1; 128 | end 129 | 130 | // VidEN generation (delaying Border 8 clocks) 131 | reg VidEN_n = 1; 132 | always @(negedge clk7) begin 133 | if (hc[3]) 134 | VidEN_n <= !Border_n; 135 | end 136 | 137 | // DataLatch generation (posedge to capture data from memory) 138 | reg DataLatch_n = 1; 139 | always @(negedge clk7) begin 140 | if (hc[0] & !hc[1] & Border_n & hc[3]) 141 | DataLatch_n <= 0; 142 | else 143 | DataLatch_n <= 1; 144 | end 145 | 146 | // AttrLatch generation (posedge to capture data from memory) 147 | reg AttrLatch_n = 1; 148 | always @(negedge clk7) begin 149 | if (hc[0] & hc[1] & Border_n & hc[3]) 150 | AttrLatch_n <= 0; 151 | else 152 | AttrLatch_n <= 1; 153 | end 154 | 155 | // SLoad generation (negedge to load shift register) 156 | reg SLoad = 0; 157 | always @(negedge clk7) begin 158 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 159 | SLoad <= 1; 160 | else 161 | SLoad <= 0; 162 | end 163 | 164 | // AOLatch generation (negedge to update attr output latch) 165 | reg AOLatch_n = 1; 166 | always @(negedge clk7) begin 167 | if (hc[0] & !hc[1] & hc[2]) 168 | AOLatch_n <= 0; 169 | else 170 | AOLatch_n <= 1; 171 | end 172 | 173 | // First buffer for bitmap 174 | reg [7:0] BitmapReg = 0; 175 | always @(negedge DataLatch_n) begin 176 | BitmapReg <= d; 177 | end 178 | 179 | // Shift register (second bitmap register) 180 | reg [7:0] SRegister = 0; 181 | always @(negedge clk7) begin 182 | if (SLoad) 183 | SRegister <= BitmapReg; 184 | else 185 | SRegister <= {SRegister[6:0],1'b0}; 186 | end 187 | 188 | // First buffer for attribute 189 | reg [7:0] AttrReg = 0; 190 | always @(negedge AttrLatch_n) begin 191 | AttrReg <= d; 192 | end 193 | 194 | // Second buffer for attribute 195 | reg [7:0] AttrOut = 0; 196 | always @(negedge AOLatch_n) begin 197 | if (!VidEN_n) 198 | AttrOut <= AttrReg; 199 | else 200 | AttrOut <= {2'b00,BorderColor,BorderColor}; 201 | end 202 | 203 | // Flash counter and pixel generation 204 | reg [4:0] FlashCnt = 0; 205 | always @(negedge VSync_n) begin 206 | FlashCnt <= FlashCnt + 1; 207 | end 208 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 209 | 210 | // RGB generation 211 | reg rI,rG,rR,rB; 212 | assign r = rR; 213 | assign g = rG; 214 | assign b = rB; 215 | assign i = rI; 216 | always @(*) begin 217 | if (HBlank_n && VBlank_n) 218 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 219 | else 220 | {rI,rG,rR,rB} = 4'b0000; 221 | end 222 | 223 | //CSync generation 224 | assign csync = HSync_n & VSync_n; 225 | 226 | // VRAM address and control line generation 227 | reg [13:0] rVA = 0; 228 | reg rVCS_n = 1; 229 | reg rVOE_n = 1; 230 | reg rVWE_n = 1; 231 | reg rVRAMInUse = 0; 232 | assign va = rVA; 233 | assign vramcs_n = rVCS_n; 234 | assign vramoe_n = rVOE_n; 235 | assign vramwe_n = rVWE_n; 236 | assign vram_in_use = rVRAMInUse; 237 | // Latches to hold delayed versions of V and H counters 238 | reg [8:0] v = 0; 239 | reg [8:0] c = 0; 240 | // Address and control line multiplexor ULA/CPU 241 | always @(negedge clk7) begin 242 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 243 | c <= hc; 244 | v <= vc; 245 | end 246 | end 247 | // Address and control line multiplexor ULA/CPU 248 | always @(*) begin 249 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present display address to VRAM 250 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 9 and 13 load display byte) 251 | rVCS_n = 0; 252 | rVOE_n = 0; 253 | rVWE_n = 1; 254 | rVRAMInUse = 1; 255 | end 256 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present attribute address to VRAM 257 | rVA = {4'b0110,v[7:3],c[7:3]}; // (cycles 11 and 15 load attr byte) 258 | rVCS_n = 0; 259 | rVOE_n = 0; 260 | rVWE_n = 1; 261 | rVRAMInUse = 1; 262 | end 263 | else begin // when VRAM is not in use by ULA, give it to CPU by putting ULA lines in high impedance mode. 264 | rVA = 14'bzzzzzzzzzzzzzz; 265 | rVCS_n = 1'bz; 266 | rVOE_n = 1'bz; 267 | rVWE_n = 1'bz; 268 | rVRAMInUse = 0; 269 | end 270 | end 271 | 272 | // CPU contention 273 | reg CPUClk = 0; 274 | assign clkcpu = CPUClk; 275 | reg ioreqtw3 = 0; 276 | reg mreqt23 = 0; 277 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 278 | (~(~a[15] | ~ioreq_n)) | 279 | (~(hc[2] | hc[3])) | 280 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 281 | wire Nor2 = (~(hc[2] | hc[3])) | 282 | ~Border_n | 283 | ~CPUClk | 284 | ioreq_n | 285 | ~ioreqtw3; 286 | wire CLKContention = ~Nor1 | ~Nor2; 287 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 288 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 289 | CPUClk <= 0; 290 | else 291 | CPUClk <= 1; 292 | end 293 | always @(posedge CPUClk) begin 294 | ioreqtw3 <= ioreq_n; 295 | mreqt23 <= mreq_n; 296 | end 297 | endmodule 298 | -------------------------------------------------------------------------------- /fpga_version/rtl/ula.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar. rodriguj@atc.us.es 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ZX Spectrum 8 | // Module Name: ula 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 1.00 - File Created 18 | // Additional Comments: GPL License policies apply to the contents of this file. 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ula( 26 | input clk14, // 14MHz master clock 27 | // CPU interfacing 28 | input [15:0] a, // Address bus from CPU (not all lines are used) 29 | input [7:0] din, // Input data bus from CPU 30 | output [7:0] dout, // Output data bus to CPU 31 | input mreq_n, // MREQ from CPU 32 | input iorq_n, // IORQ from CPU 33 | input rd_n, // RD from CPU 34 | input wr_n, // WR from CPU 35 | input rfsh_n, // RFSH from CPU 36 | output clkcpu, // CLK to CPU 37 | output msk_int_n, // Vertical retrace interrupt, to CPU 38 | // VRAM interfacing 39 | output [13:0] va, // Address bus to VRAM (16K) 40 | input [7:0] vramdout,// Data from VRAM to ULA/CPU 41 | output [7:0] vramdin,// Data from CPU to VRAM 42 | output vramoe, // 43 | output vramcs, // Control signals for VRAM 44 | output vramwe, // 45 | // ULA I/O 46 | input ear, // 47 | output mic, // I/O ports 48 | output spk, // 49 | output [7:0] kbrows, // Keyboard rows 50 | input [4:0] kbcolumns, // Keyboard columns 51 | // Video output 52 | output r, // 53 | output g, // RGB TTL signal 54 | output b, // with separate bright 55 | output i, // and composite sync 56 | output csync // 57 | ); 58 | 59 | reg [2:0] BorderColor = 3'b100; 60 | 61 | // Pixel clock 62 | reg clk7 = 0; 63 | always @(posedge clk14) 64 | clk7 <= !clk7; 65 | 66 | // Horizontal counter 67 | reg [8:0] hc = 0; 68 | always @(posedge clk7) begin 69 | if (hc==447) 70 | hc <= 0; 71 | else 72 | hc <= hc + 1; 73 | end 74 | 75 | // Vertical counter 76 | reg [8:0] vc = 0; 77 | always @(posedge clk7) begin 78 | if (hc==447) begin 79 | if (vc == 311) 80 | vc <= 0; 81 | else 82 | vc <= vc + 1; 83 | end 84 | end 85 | 86 | // HBlank generation 87 | reg HBlank_n = 1; 88 | always @(negedge clk7) begin 89 | if (`cyclestart(hc,320)) 90 | HBlank_n <= 0; 91 | else if (`cycleend(hc,415)) 92 | HBlank_n <= 1; 93 | end 94 | 95 | // HSync generation (6C ULA version) 96 | reg HSync_n = 1; 97 | always @(negedge clk7) begin 98 | if (`cyclestart(hc,344)) 99 | HSync_n <= 0; 100 | else if (`cycleend(hc,375)) 101 | HSync_n <= 1; 102 | end 103 | 104 | // VBlank generation 105 | reg VBlank_n = 1; 106 | always @(negedge clk7) begin 107 | if (`cyclestart(vc,248)) 108 | VBlank_n <= 0; 109 | else if (`cycleend(vc,255)) 110 | VBlank_n <= 1; 111 | end 112 | 113 | // VSync generation (PAL) 114 | reg VSync_n = 1; 115 | always @(negedge clk7) begin 116 | if (`cyclestart(vc,248)) 117 | VSync_n <= 0; 118 | else if (`cycleend(vc,251)) 119 | VSync_n <= 1; 120 | end 121 | 122 | // INT generation 123 | reg INT_n = 1; 124 | assign msk_int_n = INT_n; 125 | always @(negedge clk7) begin 126 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 127 | INT_n <= 0; 128 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 129 | INT_n <= 1; 130 | end 131 | 132 | // Border control signal (=0 when we're not displaying paper/ink pixels) 133 | reg Border_n = 1; 134 | always @(negedge clk7) begin 135 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 136 | Border_n <= 0; 137 | else 138 | Border_n <= 1; 139 | end 140 | 141 | // VidEN generation (delaying Border 8 clocks) 142 | reg VidEN_n = 1; 143 | always @(negedge clk7) begin 144 | if (hc[3]) 145 | VidEN_n <= !Border_n; 146 | end 147 | 148 | // DataLatch generation (posedge to capture data from memory) 149 | reg DataLatch_n = 1; 150 | always @(negedge clk7) begin 151 | if (hc[0] & !hc[1] & Border_n & hc[3]) 152 | DataLatch_n <= 0; 153 | else 154 | DataLatch_n <= 1; 155 | end 156 | 157 | // AttrLatch generation (posedge to capture data from memory) 158 | reg AttrLatch_n = 1; 159 | always @(negedge clk7) begin 160 | if (hc[0] & hc[1] & Border_n & hc[3]) 161 | AttrLatch_n <= 0; 162 | else 163 | AttrLatch_n <= 1; 164 | end 165 | 166 | // SLoad generation (negedge to load shift register) 167 | reg SLoad = 0; 168 | always @(negedge clk7) begin 169 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 170 | SLoad <= 1; 171 | else 172 | SLoad <= 0; 173 | end 174 | 175 | // AOLatch generation (negedge to update attr output latch) 176 | reg AOLatch_n = 1; 177 | always @(negedge clk7) begin 178 | if (hc[0] & !hc[1] & hc[2]) 179 | AOLatch_n <= 0; 180 | else 181 | AOLatch_n <= 1; 182 | end 183 | 184 | // First buffer for bitmap 185 | reg [7:0] BitmapReg = 0; 186 | always @(negedge DataLatch_n) begin 187 | BitmapReg <= vramdout; 188 | end 189 | 190 | // Shift register (second bitmap register) 191 | reg [7:0] SRegister = 0; 192 | always @(negedge clk7) begin 193 | if (SLoad) 194 | SRegister <= BitmapReg; 195 | else 196 | SRegister <= {SRegister[6:0],1'b0}; 197 | end 198 | 199 | // First buffer for attribute 200 | reg [7:0] AttrReg = 0; 201 | always @(negedge AttrLatch_n) begin 202 | AttrReg <= vramdout; 203 | end 204 | 205 | // Second buffer for attribute 206 | reg [7:0] AttrOut = 0; 207 | always @(negedge AOLatch_n) begin 208 | if (!VidEN_n) 209 | AttrOut <= AttrReg; 210 | else 211 | AttrOut <= {2'b00,BorderColor,BorderColor}; 212 | end 213 | 214 | // Flash counter and pixel generation 215 | reg [4:0] FlashCnt = 0; 216 | always @(negedge VSync_n) begin 217 | FlashCnt <= FlashCnt + 1; 218 | end 219 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 220 | 221 | // RGB generation 222 | reg rI,rG,rR,rB; 223 | assign r = rR; 224 | assign g = rG; 225 | assign b = rB; 226 | assign i = rI; 227 | always @(*) begin 228 | if (HBlank_n && VBlank_n) 229 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 230 | else 231 | {rI,rG,rR,rB} = 4'b0000; 232 | end 233 | 234 | //CSync generation 235 | assign csync = HSync_n & VSync_n; 236 | 237 | // VRAM address and control line generation 238 | reg [13:0] rVA = 0; 239 | reg rVCS = 0; 240 | reg rVOE = 0; 241 | reg rVWE = 0; 242 | assign va = rVA; 243 | assign vramcs = rVCS; 244 | assign vramoe = rVOE; 245 | assign vramwe = rVWE; 246 | // Latches to hold delayed versions of V and H counters 247 | reg [8:0] v = 0; 248 | reg [8:0] c = 0; 249 | // Address and control line multiplexor ULA/CPU 250 | always @(negedge clk7) begin 251 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 252 | c <= hc; 253 | v <= vc; 254 | end 255 | end 256 | // Address and control line multiplexor ULA/CPU 257 | always @(*) begin 258 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present display address to VRAM 259 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 9 and 13 load display byte) 260 | rVCS = 1; 261 | rVOE = !hc[0]; 262 | rVWE = 0; 263 | end 264 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present attribute address to VRAM 265 | rVA = {4'b0110,v[7:3],c[7:3]}; // (cycles 11 and 15 load attr byte) 266 | rVCS = 1; 267 | rVOE = !hc[0]; 268 | rVWE = 0; 269 | end 270 | else if (Border_n && hc[3:0]==4'b0000) begin 271 | rVA = a[13:0]; 272 | rVCS = 0; 273 | rVOE = 0; 274 | rVWE = 0; 275 | end 276 | else begin // when VRAM is not in use by ULA, give it to CPU 277 | rVA = a[13:0]; 278 | rVCS = !a[15] & a[14] & !mreq_n; 279 | rVOE = !rd_n; 280 | rVWE = !wr_n; 281 | end 282 | end 283 | 284 | // CPU contention 285 | reg CPUClk = 0; 286 | assign clkcpu = CPUClk; 287 | reg ioreqtw3 = 0; 288 | reg mreqt23 = 0; 289 | wire ioreq_n = a[0] | iorq_n; 290 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 291 | (~(~a[15] | ~ioreq_n)) | 292 | (~(hc[2] | hc[3])) | 293 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 294 | wire Nor2 = (~(hc[2] | hc[3])) | 295 | ~Border_n | 296 | ~CPUClk | 297 | ioreq_n | 298 | ~ioreqtw3; 299 | wire CLKContention = ~Nor1 | ~Nor2; 300 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 301 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 302 | CPUClk <= 0; 303 | else 304 | CPUClk <= 1; 305 | end 306 | always @(posedge CPUClk) begin 307 | ioreqtw3 <= ioreq_n; 308 | mreqt23 <= mreq_n; 309 | end 310 | 311 | // ULA-CPU interface 312 | assign dout = (!a[15] & a[14] & !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly 313 | (!iorq_n & !a[0])? {1'b1,ear,1'b1,kbcolumns} : // CPU reads keyboard and EAR state 314 | (Border_n)? AttrReg : // to emulate 315 | 8'hFF; // port FF 316 | assign vramdin = din; // The CPU doesn't need to share the memory input data bus with the ULA 317 | assign kbrows = {a[11]? 1'bz : 1'b0, // high impedance or 0, as if diodes were been placed in between 318 | a[10]? 1'bz : 1'b0, // if the keyboard matrix is to be implemented within the FPGA, then 319 | a[9]? 1'bz : 1'b0, // there's no need to do this. 320 | a[12]? 1'bz : 1'b0, 321 | a[13]? 1'bz : 1'b0, 322 | a[8]? 1'bz : 1'b0, 323 | a[14]? 1'bz : 1'b0, 324 | a[15]? 1'bz : 1'b0 }; 325 | // assign kbrows = {a[8]? 1'bz : 1'b0, // high impedance or 0, as if diodes were been placed in between 326 | // a[9]? 1'bz : 1'b0, // if the keyboard matrix is to be implemented within the FPGA, then 327 | // a[10]? 1'bz : 1'b0, // there's no need to do this. 328 | // a[11]? 1'bz : 1'b0, 329 | // a[12]? 1'bz : 1'b0, 330 | // a[13]? 1'bz : 1'b0, 331 | // a[14]? 1'bz : 1'b0, 332 | // a[15]? 1'bz : 1'b0 }; 333 | reg rMic = 0; 334 | reg rSpk = 0; 335 | assign mic = rMic; 336 | assign spk = rSpk; 337 | always @(negedge clk7) begin 338 | if (!iorq_n & !a[0] & !wr_n) 339 | {rSpk,rMic,BorderColor} <= din[5:0]; 340 | end 341 | endmodule 342 | -------------------------------------------------------------------------------- /fpga_version/rtl/ula_with_timex_hicolor_support.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar. rodriguj@atc.us.es 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ZX Spectrum 8 | // Module Name: ula 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 1.00 - File Created 18 | // Additional Comments: GPL License policies apply to the contents of this file. 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ula( 26 | input clk14, // 14MHz master clock 27 | input reset, // to reset the ULA to normal color mode. 28 | // CPU interfacing 29 | input [15:0] a, // Address bus from CPU (not all lines are used) 30 | input [7:0] din, // Input data bus from CPU 31 | output [7:0] dout, // Output data bus to CPU 32 | input mreq_n, // MREQ from CPU 33 | input iorq_n, // IORQ from CPU 34 | input rd_n, // RD from CPU 35 | input wr_n, // WR from CPU 36 | input rfsh_n, // RFSH from CPU 37 | output clkcpu, // CLK to CPU 38 | output msk_int_n, // Vertical retrace interrupt, to CPU 39 | // VRAM interfacing 40 | output [13:0] va, // Address bus to VRAM (16K) 41 | input [7:0] vramdout,// Data from VRAM to ULA/CPU 42 | output [7:0] vramdin,// Data from CPU to VRAM 43 | output vramoe, // 44 | output vramcs, // Control signals for VRAM 45 | output vramwe, // 46 | // ULA I/O 47 | input ear, // 48 | output mic, // I/O ports 49 | output spk, // 50 | output [7:0] kbrows, // Keyboard rows 51 | input [4:0] kbcolumns, // Keyboard columns 52 | // Video output 53 | output r, // 54 | output g, // RGB TTL signal 55 | output b, // with separate bright 56 | output i, // and composite sync 57 | output csync // 58 | ); 59 | 60 | reg [2:0] BorderColor = 3'b100; 61 | reg TimexHiColorMode = 0; 62 | 63 | // Pixel clock 64 | reg clk7 = 0; 65 | always @(posedge clk14) 66 | clk7 <= !clk7; 67 | 68 | // Horizontal counter 69 | reg [8:0] hc = 0; 70 | always @(posedge clk7) begin 71 | if (hc==447) 72 | hc <= 0; 73 | else 74 | hc <= hc + 1; 75 | end 76 | 77 | // Vertical counter 78 | reg [8:0] vc = 0; 79 | always @(posedge clk7) begin 80 | if (hc==447) begin 81 | if (vc == 311) 82 | vc <= 0; 83 | else 84 | vc <= vc + 1; 85 | end 86 | end 87 | 88 | // HBlank generation 89 | reg HBlank_n = 1; 90 | always @(negedge clk7) begin 91 | if (`cyclestart(hc,320)) 92 | HBlank_n <= 0; 93 | else if (`cycleend(hc,415)) 94 | HBlank_n <= 1; 95 | end 96 | 97 | // HSync generation (6C ULA version) 98 | reg HSync_n = 1; 99 | always @(negedge clk7) begin 100 | if (`cyclestart(hc,344)) 101 | HSync_n <= 0; 102 | else if (`cycleend(hc,375)) 103 | HSync_n <= 1; 104 | end 105 | 106 | // VBlank generation 107 | reg VBlank_n = 1; 108 | always @(negedge clk7) begin 109 | if (`cyclestart(vc,248)) 110 | VBlank_n <= 0; 111 | else if (`cycleend(vc,255)) 112 | VBlank_n <= 1; 113 | end 114 | 115 | // VSync generation (PAL) 116 | reg VSync_n = 1; 117 | always @(negedge clk7) begin 118 | if (`cyclestart(vc,248)) 119 | VSync_n <= 0; 120 | else if (`cycleend(vc,251)) 121 | VSync_n <= 1; 122 | end 123 | 124 | // INT generation 125 | reg INT_n = 1; 126 | assign msk_int_n = INT_n; 127 | always @(negedge clk7) begin 128 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 129 | INT_n <= 0; 130 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 131 | INT_n <= 1; 132 | end 133 | 134 | // Border control signal (=0 when we're not displaying paper/ink pixels) 135 | reg Border_n = 1; 136 | always @(negedge clk7) begin 137 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 138 | Border_n <= 0; 139 | else 140 | Border_n <= 1; 141 | end 142 | 143 | // VidEN generation (delaying Border 8 clocks) 144 | reg VidEN_n = 1; 145 | always @(negedge clk7) begin 146 | if (hc[3]) 147 | VidEN_n <= !Border_n; 148 | end 149 | 150 | // DataLatch generation (posedge to capture data from memory) 151 | reg DataLatch_n = 1; 152 | always @(negedge clk7) begin 153 | if (hc[0] & !hc[1] & Border_n & hc[3]) 154 | DataLatch_n <= 0; 155 | else 156 | DataLatch_n <= 1; 157 | end 158 | 159 | // AttrLatch generation (posedge to capture data from memory) 160 | reg AttrLatch_n = 1; 161 | always @(negedge clk7) begin 162 | if (hc[0] & hc[1] & Border_n & hc[3]) 163 | AttrLatch_n <= 0; 164 | else 165 | AttrLatch_n <= 1; 166 | end 167 | 168 | // SLoad generation (negedge to load shift register) 169 | reg SLoad = 0; 170 | always @(negedge clk7) begin 171 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 172 | SLoad <= 1; 173 | else 174 | SLoad <= 0; 175 | end 176 | 177 | // AOLatch generation (negedge to update attr output latch) 178 | reg AOLatch_n = 1; 179 | always @(negedge clk7) begin 180 | if (hc[0] & !hc[1] & hc[2]) 181 | AOLatch_n <= 0; 182 | else 183 | AOLatch_n <= 1; 184 | end 185 | 186 | // First buffer for bitmap 187 | reg [7:0] BitmapReg = 0; 188 | always @(negedge DataLatch_n) begin 189 | BitmapReg <= vramdout; 190 | end 191 | 192 | // Shift register (second bitmap register) 193 | reg [7:0] SRegister = 0; 194 | always @(negedge clk7) begin 195 | if (SLoad) 196 | SRegister <= BitmapReg; 197 | else 198 | SRegister <= {SRegister[6:0],1'b0}; 199 | end 200 | 201 | // First buffer for attribute 202 | reg [7:0] AttrReg = 0; 203 | always @(negedge AttrLatch_n) begin 204 | AttrReg <= vramdout; 205 | end 206 | 207 | // Second buffer for attribute 208 | reg [7:0] AttrOut = 0; 209 | always @(negedge AOLatch_n) begin 210 | if (!VidEN_n) 211 | AttrOut <= AttrReg; 212 | else 213 | AttrOut <= {2'b00,BorderColor,BorderColor}; 214 | end 215 | 216 | // Flash counter and pixel generation 217 | reg [4:0] FlashCnt = 0; 218 | always @(negedge VSync_n) begin 219 | FlashCnt <= FlashCnt + 1; 220 | end 221 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 222 | 223 | // RGB generation 224 | reg rI,rG,rR,rB; 225 | assign r = rR; 226 | assign g = rG; 227 | assign b = rB; 228 | assign i = rI; 229 | always @(*) begin 230 | if (HBlank_n && VBlank_n) 231 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 232 | else 233 | {rI,rG,rR,rB} = 4'b0000; 234 | end 235 | 236 | //CSync generation 237 | assign csync = HSync_n & VSync_n; 238 | 239 | // VRAM address and control line generation 240 | reg [13:0] rVA = 0; 241 | reg rVCS = 0; 242 | reg rVOE = 0; 243 | reg rVWE = 0; 244 | assign va = rVA; 245 | assign vramcs = rVCS; 246 | assign vramoe = rVOE; 247 | assign vramwe = rVWE; 248 | // Latches to hold delayed versions of V and H counters 249 | reg [8:0] v = 0; 250 | reg [8:0] c = 0; 251 | // Address and control line multiplexor ULA/CPU 252 | always @(negedge clk7) begin 253 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 254 | c <= hc; 255 | v <= vc; 256 | end 257 | end 258 | // Address and control line multiplexor ULA/CPU 259 | always @(*) begin 260 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present display address to VRAM 261 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 9 and 13 load display byte) 262 | rVCS = 1; 263 | rVOE = !hc[0]; 264 | rVWE = 0; 265 | end 266 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present attribute address to VRAM 267 | rVA = (TimexHiColorMode)? {1'b1,v[7:6],v[2:0],v[5:3],c[7:3]} : // (cycles 11 and 15 load attr byte). 268 | {4'b0110,v[7:3],c[7:3]}; // Attribute address depends upon the mode selected 269 | rVCS = 1; 270 | rVOE = !hc[0]; 271 | rVWE = 0; 272 | end 273 | else if (Border_n && hc[3:0]==4'b0000) begin 274 | rVA = a[13:0]; 275 | rVCS = 0; 276 | rVOE = 0; 277 | rVWE = 0; 278 | end 279 | else begin // when VRAM is not in use by ULA, give it to CPU 280 | rVA = a[13:0]; 281 | rVCS = !a[15] & a[14] & !mreq_n; 282 | rVOE = !rd_n; 283 | rVWE = !wr_n; 284 | end 285 | end 286 | 287 | // CPU contention 288 | reg CPUClk = 0; 289 | assign clkcpu = CPUClk; 290 | reg ioreqtw3 = 0; 291 | reg mreqt23 = 0; 292 | wire ioreq_n = a[0] | iorq_n; 293 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 294 | (~(~a[15] | ~ioreq_n)) | 295 | (~(hc[2] | hc[3])) | 296 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 297 | wire Nor2 = (~(hc[2] | hc[3])) | 298 | ~Border_n | 299 | ~CPUClk | 300 | ioreq_n | 301 | ~ioreqtw3; 302 | wire CLKContention = ~Nor1 | ~Nor2; 303 | 304 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 305 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 306 | CPUClk <= 0; 307 | else 308 | CPUClk <= 1; 309 | end 310 | always @(posedge CPUClk) begin 311 | ioreqtw3 <= ioreq_n; 312 | mreqt23 <= mreq_n; 313 | end 314 | 315 | // ULA-CPU interface 316 | assign dout = (!a[15] & a[14] & !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly 317 | (!iorq_n & !a[0])? {1'b1,ear,1'b1,kbcolumns} : // CPU reads keyboard and EAR state 318 | (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported. 319 | (Border_n)? AttrReg : // to emulate 320 | 8'hFF; // port FF (well, cannot be actually FF anymore) 321 | assign vramdin = din; // The CPU doesn't need to share the memory input data bus with the ULA 322 | assign kbrows = {a[11]? 1'bz : 1'b0, // high impedance or 0, as if diodes were been placed in between 323 | a[10]? 1'bz : 1'b0, // if the keyboard matrix is to be implemented within the FPGA, then 324 | a[9]? 1'bz : 1'b0, // there's no need to do this. 325 | a[12]? 1'bz : 1'b0, 326 | a[13]? 1'bz : 1'b0, 327 | a[8]? 1'bz : 1'b0, 328 | a[14]? 1'bz : 1'b0, 329 | a[15]? 1'bz : 1'b0 }; 330 | reg rMic = 0; 331 | reg rSpk = 0; 332 | assign mic = rMic; 333 | assign spk = rSpk; 334 | always @(negedge clk7 or posedge reset) begin 335 | if (reset) 336 | TimexHiColorMode <= 0; 337 | else if (!iorq_n && a[7:0]==8'hFF && !wr_n) 338 | TimexHiColorMode <= din[1]; 339 | else if (!iorq_n & !a[0] & !wr_n) 340 | {rSpk,rMic,BorderColor} <= din[5:0]; 341 | end 342 | endmodule 343 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/signalview.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | clk7 16 | clk7 17 | 18 | 19 | Counters 20 | label 21 | 128 128 255 22 | 230 230 230 23 | 24 | 25 | hc[8:0] 26 | hc[8:0] 27 | UNSIGNEDDECRADIX 28 | 29 | 30 | vc[8:0] 31 | vc[8:0] 32 | UNSIGNEDDECRADIX 33 | 34 | 35 | Syncs 36 | label 37 | 128 128 255 38 | 230 230 230 39 | 40 | 41 | HBlank_n 42 | HBlank_n 43 | 44 | 45 | HSync_n 46 | HSync_n 47 | 48 | 49 | VSync_n 50 | VSync_n 51 | 52 | 53 | msk_int_n 54 | msk_int_n 55 | 56 | 57 | Control clocks 58 | label 59 | 128 128 255 60 | 230 230 230 61 | 62 | 63 | Border_n 64 | Border_n 65 | 66 | 67 | VidEN_n 68 | VidEN_n 69 | 70 | 71 | DataLatch_n 72 | DataLatch_n 73 | 74 | 75 | AttrLatch_n 76 | AttrLatch_n 77 | 78 | 79 | SLoad 80 | SLoad 81 | 82 | 83 | AOLatch_n 84 | AOLatch_n 85 | 86 | 87 | Data 88 | label 89 | 128 128 255 90 | 230 230 230 91 | 92 | 93 | va[13:0] 94 | va[13:0] 95 | HEXRADIX 96 | 97 | 98 | BitmapReg[7:0] 99 | BitmapReg[7:0] 100 | HEXRADIX 101 | 102 | 103 | SRegister[7:0] 104 | SRegister[7:0] 105 | HEXRADIX 106 | 107 | 108 | AttrReg[7:0] 109 | AttrReg[7:0] 110 | HEXRADIX 111 | 112 | 113 | AttrOut[7:0] 114 | AttrOut[7:0] 115 | HEXRADIX 116 | 117 | 118 | TV Output 119 | label 120 | 128 128 255 121 | 230 230 230 122 | 123 | 124 | RGB 125 | label 126 | UNSIGNEDDECRADIX 127 | 128 | g 129 | g 130 | 131 | 132 | r 133 | r 134 | 135 | 136 | b 137 | b 138 | 139 | 140 | 141 | i 142 | i 143 | 144 | 145 | csync 146 | csync 147 | 148 | 149 | Contention handler 150 | label 151 | 128 128 255 152 | 230 230 230 153 | 154 | 155 | CLKContention 156 | CLKContention 157 | 158 | 159 | Nor1 160 | Nor1 161 | 162 | 163 | Nor2 164 | Nor2 165 | 166 | 167 | CPU 168 | label 169 | 128 128 255 170 | 230 230 230 171 | 172 | 173 | clk7 174 | clk7 175 | 176 | 177 | clk 178 | clk 179 | 180 | 181 | a[15:0] 182 | a[15:0] 183 | HEXRADIX 184 | 185 | 186 | mreq_n 187 | mreq_n 188 | 189 | 190 | iorq_n 191 | iorq_n 192 | 193 | 194 | wr_n 195 | wr_n 196 | 197 | 198 | d[7:0] 199 | d[7:0] 200 | UNSIGNEDDECRADIX 201 | 202 | 203 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/ula.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ULA 8 | // Module Name: ula_reference_design 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 0.01 - File Created 18 | // Additional Comments: 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ula( 26 | input clk14, // 14MHz master clock 27 | // CPU interfacing 28 | input [15:0] a, // Address bus from CPU (not all lines are used) 29 | input [7:0] din, // Input data bus from CPU 30 | output [7:0] dout, // Output data bus to CPU 31 | input mreq_n, // MREQ from CPU 32 | input iorq_n, // IORQ from CPU 33 | input rd_n, // RD from CPU 34 | input wr_n, // WR from CPU 35 | input rfsh_n, // RFSH from CPU 36 | output clkcpu, // CLK to CPU 37 | output msk_int_n, // Vertical retrace interrupt, to CPU 38 | // VRAM interfacing 39 | output [13:0] va, // Address bus to VRAM (16K) 40 | input [7:0] vramdout,// Data from VRAM to ULA/CPU 41 | output [7:0] vramdin,// Data from CPU to VRAM 42 | output vramoe, // 43 | output vramcs, // Control signals for VRAM 44 | output vramwe, // 45 | // ULA I/O 46 | input ear, // 47 | output mic, // I/O ports 48 | output spk, // 49 | output [7:0] kbrows, // Keyboard rows 50 | input [4:0] kbcolumns, // Keyboard columns 51 | // Video output 52 | output r, // 53 | output g, // RGB TTL signal 54 | output b, // with separate bright 55 | output i, // and composite sync 56 | output csync // 57 | ); 58 | 59 | reg [2:0] BorderColor = 3'b100; 60 | 61 | // Pixel clock 62 | reg clk7 = 0; 63 | always @(posedge clk14) 64 | clk7 <= !clk7; 65 | 66 | // Horizontal counter 67 | reg [8:0] hc = 0; 68 | always @(posedge clk7) begin 69 | if (hc==447) 70 | hc <= 0; 71 | else 72 | hc <= hc + 1; 73 | end 74 | 75 | // Vertical counter 76 | reg [8:0] vc = 0; 77 | always @(posedge clk7) begin 78 | if (hc==447) begin 79 | if (vc == 311) 80 | vc <= 0; 81 | else 82 | vc <= vc + 1; 83 | end 84 | end 85 | 86 | // HBlank generation 87 | reg HBlank_n = 1; 88 | always @(negedge clk7) begin 89 | if (`cyclestart(hc,320)) 90 | HBlank_n <= 0; 91 | else if (`cycleend(hc,415)) 92 | HBlank_n <= 1; 93 | end 94 | 95 | // HSync generation (6C ULA version) 96 | reg HSync_n = 1; 97 | always @(negedge clk7) begin 98 | if (`cyclestart(hc,344)) 99 | HSync_n <= 0; 100 | else if (`cycleend(hc,375)) 101 | HSync_n <= 1; 102 | end 103 | 104 | // VBlank generation 105 | reg VBlank_n = 1; 106 | always @(negedge clk7) begin 107 | if (`cyclestart(vc,248)) 108 | VBlank_n <= 0; 109 | else if (`cycleend(vc,255)) 110 | VBlank_n <= 1; 111 | end 112 | 113 | // VSync generation (PAL) 114 | reg VSync_n = 1; 115 | always @(negedge clk7) begin 116 | if (`cyclestart(vc,248)) 117 | VSync_n <= 0; 118 | else if (`cycleend(vc,251)) 119 | VSync_n <= 1; 120 | end 121 | 122 | // INT generation 123 | reg INT_n = 1; 124 | assign msk_int_n = INT_n; 125 | always @(negedge clk7) begin 126 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 127 | INT_n <= 0; 128 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 129 | INT_n <= 1; 130 | end 131 | 132 | // Border control signal (=0 when we're not displaying paper/ink pixels) 133 | reg Border_n = 1; 134 | always @(negedge clk7) begin 135 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 136 | Border_n <= 0; 137 | else 138 | Border_n <= 1; 139 | end 140 | 141 | // VidEN generation (delaying Border 8 clocks) 142 | reg VidEN_n = 1; 143 | always @(negedge clk7) begin 144 | if (hc[3]) 145 | VidEN_n <= !Border_n; 146 | end 147 | 148 | // DataLatch generation (posedge to capture data from memory) 149 | reg DataLatch_n = 1; 150 | always @(negedge clk7) begin 151 | if (hc[0] & !hc[1] & Border_n & hc[3]) 152 | DataLatch_n <= 0; 153 | else 154 | DataLatch_n <= 1; 155 | end 156 | 157 | // AttrLatch generation (posedge to capture data from memory) 158 | reg AttrLatch_n = 1; 159 | always @(negedge clk7) begin 160 | if (hc[0] & hc[1] & Border_n & hc[3]) 161 | AttrLatch_n <= 0; 162 | else 163 | AttrLatch_n <= 1; 164 | end 165 | 166 | // SLoad generation (negedge to load shift register) 167 | reg SLoad = 0; 168 | always @(negedge clk7) begin 169 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 170 | SLoad <= 1; 171 | else 172 | SLoad <= 0; 173 | end 174 | 175 | // AOLatch generation (negedge to update attr output latch) 176 | reg AOLatch_n = 1; 177 | always @(negedge clk7) begin 178 | if (hc[0] & !hc[1] & hc[2]) 179 | AOLatch_n <= 0; 180 | else 181 | AOLatch_n <= 1; 182 | end 183 | 184 | // First buffer for bitmap 185 | reg [7:0] BitmapReg = 0; 186 | always @(negedge DataLatch_n) begin 187 | BitmapReg <= vramdout; 188 | end 189 | 190 | // Shift register (second bitmap register) 191 | reg [7:0] SRegister = 0; 192 | always @(negedge clk7) begin 193 | if (SLoad) 194 | SRegister <= BitmapReg; 195 | else 196 | SRegister <= {SRegister[6:0],1'b0}; 197 | end 198 | 199 | // First buffer for attribute 200 | reg [7:0] AttrReg = 0; 201 | always @(negedge AttrLatch_n) begin 202 | AttrReg <= vramdout; 203 | end 204 | 205 | // Second buffer for attribute 206 | reg [7:0] AttrOut = 0; 207 | always @(negedge AOLatch_n) begin 208 | if (!VidEN_n) 209 | AttrOut <= AttrReg; 210 | else 211 | AttrOut <= {2'b00,BorderColor,BorderColor}; 212 | end 213 | 214 | // Flash counter and pixel generation 215 | reg [4:0] FlashCnt = 0; 216 | always @(negedge VSync_n) begin 217 | FlashCnt <= FlashCnt + 1; 218 | end 219 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 220 | 221 | // RGB generation 222 | reg rI,rG,rR,rB; 223 | assign r = rR; 224 | assign g = rG; 225 | assign b = rB; 226 | assign i = rI; 227 | always @(*) begin 228 | if (HBlank_n && VBlank_n) 229 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 230 | else 231 | {rI,rG,rR,rB} = 4'b0000; 232 | end 233 | 234 | //CSync generation 235 | assign csync = HSync_n & VSync_n; 236 | 237 | // VRAM address and control line generation 238 | reg [13:0] rVA = 0; 239 | reg rVCS = 0; 240 | reg rVOE = 0; 241 | reg rVWE = 0; 242 | assign va = rVA; 243 | assign vramcs = rVCS; 244 | assign vramoe = rVOE; 245 | assign vramwe = rVWE; 246 | // Latches to hold delayed versions of V and H counters 247 | reg [8:0] v = 0; 248 | reg [8:0] c = 0; 249 | // Address and control line multiplexor ULA/CPU 250 | // always @(negedge clk7) begin 251 | // if (!Border_n || hc[3:0]<=4'b0111) begin // when VRAM is not in use by ULA, give it to CPU 252 | // rVA <= a[13:0]; 253 | // rVCS <= !a[15] & a[14] & !mreq_n; 254 | // rVOE <= !rd_n; 255 | // rVWE <= !wr_n; 256 | // end 257 | // if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 258 | // c <= hc; 259 | // v <= vc; 260 | // end 261 | // if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1100)) begin // cycles 8 and 12: present display address to VRAM 262 | // rVA <= {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 9 and 13 load display byte) 263 | // rVCS <= 1; 264 | // rVOE <= 1; 265 | // rVWE <= 0; 266 | // end 267 | // if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1110)) begin // cycles 10 and 14: present attribute address to VRAM 268 | // rVA <= {4'b0110,v[7:3],c[7:3]}; // (cycles 11 and 15 load attr byte) 269 | // rVCS <= 1; 270 | // rVOE <= 1; 271 | // rVWE <= 0; 272 | // end 273 | // end 274 | 275 | always @(negedge clk7) begin 276 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 277 | c <= hc; 278 | v <= vc; 279 | end 280 | end 281 | // Address and control line multiplexor ULA/CPU 282 | always @(*) begin 283 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present display address to VRAM 284 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 9 and 13 load display byte) 285 | rVCS = 1; 286 | rVOE = 1; 287 | rVWE = 0; 288 | end 289 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present attribute address to VRAM 290 | rVA = {4'b0110,v[7:3],c[7:3]}; // (cycles 11 and 15 load attr byte) 291 | rVCS = 1; 292 | rVOE = 1; 293 | rVWE = 0; 294 | end 295 | else begin // when VRAM is not in use by ULA, give it to CPU 296 | rVA = a[13:0]; 297 | rVCS = !a[15] & a[14] & !mreq_n; 298 | rVOE = !rd_n; 299 | rVWE = !wr_n; 300 | end 301 | end 302 | 303 | // CPU contention 304 | // reg CPUClk = 0; 305 | // assign clkcpu = CPUClk; 306 | // reg [3:0] AllowedCycleCnt = 4'b0000; 307 | // wire AllowedCycle = AllowedCycleCnt[0]; // =1 if this is T2 or T3 of a mem access or T3 or T4 of a I/O access 308 | // wire VRAMAccess = !a[15] & a[14] & mreq_n & rfsh_n & CPUClk; // =1 if a VRAM access is about to begin from the CPU 309 | // wire IOAccess = !iorq_n & !a[0] & CPUClk; // =1 if an ULA I/O request has just started from the CPU 310 | // wire CausesForContention = VRAMAccess || IOAccess; // =1 if a request from the CPU uses shared resources 311 | // wire MayHaveContention = (Border_n && (hc[3] || hc[2]))? 1 : 0; // =1 if the ULA is using, or about to use the bus, so it may contend 312 | // wire CLKContention = CausesForContention && MayHaveContention && !AllowedCycle; // =1 if CPU CLK has to be stopped 313 | // 314 | // // state machine to calculate when to contend 315 | // reg [1:0] SMCont = 1; 316 | // always @(posedge clk7) begin 317 | // case (SMCont) 318 | // 1 : begin 319 | // if (CLKContention) begin 320 | // SMCont <= 2; 321 | // end 322 | // else if (CausesForContention && !MayHaveContention && !AllowedCycle) begin 323 | // AllowedCycleCnt <= 4'b1111; //CHECK: is it necesary to change this for 7MHz CPU? (00011) 324 | // SMCont <= 3; 325 | // end 326 | // end 327 | // 2 : begin 328 | // if (!MayHaveContention) begin 329 | // AllowedCycleCnt <= 4'b1111; //CHECK: is it necesary to change this for 7MHz CPU? (00011) 330 | // SMCont <= 3; 331 | // end 332 | // end 333 | // 3 : begin 334 | // if (AllowedCycle) begin 335 | // AllowedCycleCnt <= {1'b0, AllowedCycleCnt[3:1] }; 336 | // end 337 | // else begin 338 | // SMCont <= 1; 339 | // end 340 | // end 341 | // endcase 342 | // end 343 | // 344 | // always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 345 | // if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 346 | // CPUClk <= 0; 347 | // else 348 | // CPUClk <= 1; 349 | // end 350 | 351 | // CPU contention 352 | reg CPUClk = 0; 353 | assign clkcpu = CPUClk; 354 | reg ioreqtw3 = 0; 355 | reg mreqt23 = 0; 356 | wire ioreq_n = a[0] | iorq_n; 357 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 358 | (~(~a[15] | ~ioreq_n)) | 359 | (~(hc[2] | hc[3])) | 360 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 361 | wire Nor2 = (~(hc[2] | hc[3])) | 362 | ~Border_n | 363 | ~CPUClk | 364 | ioreq_n | 365 | ~ioreqtw3; 366 | wire CLKContention = ~Nor1 | ~Nor2; 367 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 368 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 369 | CPUClk <= 0; 370 | else 371 | CPUClk <= 1; 372 | end 373 | always @(posedge CPUClk) begin 374 | ioreqtw3 <= ioreq_n; 375 | mreqt23 <= mreq_n; 376 | end 377 | 378 | // ULA-CPU interface 379 | assign dout = (!a[15] & a[14] & !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly 380 | (!iorq_n & !a[0])? {1'b1,ear,1'b1,kbcolumns} : // CPU reads keyboard and EAR state 381 | (Border_n)? vramdout : // to emulate 382 | 8'hFF; // port FF 383 | assign vramdin = din; // The CPU doesn't need to share the memory input data bus with the ULA 384 | assign kbrows = {a[11]? 1'bz : 0, // high impedance or 0, as if diodes were been placed in between 385 | a[10]? 1'bz : 0, // if the keyboard matrix is to be implemented within the FPGA, then 386 | a[9]? 1'bz : 0, // there's no need to do this. 387 | a[12]? 1'bz : 0, 388 | a[13]? 1'bz : 0, 389 | a[8]? 1'bz : 0, 390 | a[14]? 1'bz : 0, 391 | a[15]? 1'bz : 0 }; 392 | reg rMic = 0; 393 | reg rSpk = 0; 394 | assign mic = rMic; 395 | assign spk = rSpk; 396 | always @(negedge clk7) begin 397 | if (!iorq_n & !a[0] & !wr_n) 398 | {rSpk,rMic,BorderColor} <= din[5:0]; 399 | end 400 | endmodule 401 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/signalview_ulaplus.wcfg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | clk7 16 | clk7 17 | 18 | 19 | Counters 20 | label 21 | 128 128 255 22 | 230 230 230 23 | 24 | 25 | hc[8:0] 26 | hc[8:0] 27 | UNSIGNEDDECRADIX 28 | 29 | 30 | vc[8:0] 31 | vc[8:0] 32 | UNSIGNEDDECRADIX 33 | 34 | 35 | Syncs 36 | label 37 | 128 128 255 38 | 230 230 230 39 | 40 | 41 | HBlank_n 42 | HBlank_n 43 | 44 | 45 | HSync_n 46 | HSync_n 47 | 48 | 49 | VSync_n 50 | VSync_n 51 | 52 | 53 | msk_int_n 54 | msk_int_n 55 | 56 | 57 | Control clocks 58 | label 59 | 128 128 255 60 | 230 230 230 61 | 62 | 63 | Border_n 64 | Border_n 65 | 66 | 67 | VidEN_n 68 | VidEN_n 69 | 70 | 71 | DataLatch_n 72 | DataLatch_n 73 | 74 | 75 | AttrLatch_n 76 | AttrLatch_n 77 | 78 | 79 | SLoad 80 | SLoad 81 | 82 | 83 | AOLatch_n 84 | AOLatch_n 85 | 86 | 87 | Data 88 | label 89 | 128 128 255 90 | 230 230 230 91 | 92 | 93 | clk14 94 | clk14 95 | 96 | 97 | va[13:0] 98 | va[13:0] 99 | HEXRADIX 100 | 101 | 102 | BitmapReg[7:0] 103 | BitmapReg[7:0] 104 | HEXRADIX 105 | 106 | 107 | SRegister[7:0] 108 | SRegister[7:0] 109 | HEXRADIX 110 | 111 | 112 | AttrReg[7:0] 113 | AttrReg[7:0] 114 | HEXRADIX 115 | 116 | 117 | AttrOut[7:0] 118 | AttrOut[7:0] 119 | HEXRADIX 120 | 121 | 122 | ULA+ palette address and data buses 123 | label 124 | 128 128 255 125 | 230 230 230 126 | 127 | 128 | paletteaddr[5:0] 129 | paletteaddr[5:0] 130 | UNSIGNEDDECRADIX 131 | 132 | 133 | ULAPlusPaper[7:0] 134 | ULAPlusPaper[7:0] 135 | UNSIGNEDDECRADIX 136 | 137 | 138 | ULAPlusInk[7:0] 139 | ULAPlusInk[7:0] 140 | UNSIGNEDDECRADIX 141 | 142 | 143 | ULAPlusBorder[7:0] 144 | ULAPlusBorder[7:0] 145 | UNSIGNEDDECRADIX 146 | 147 | 148 | ULAPlusPaperOut[7:0] 149 | ULAPlusPaperOut[7:0] 150 | UNSIGNEDDECRADIX 151 | 152 | 153 | ULAPlusInkOut[7:0] 154 | ULAPlusInkOut[7:0] 155 | UNSIGNEDDECRADIX 156 | 157 | 158 | rRGBULAPlus[7:0] 159 | rRGBULAPlus[7:0] 160 | UNSIGNEDDECRADIX 161 | 162 | 163 | TV Output 164 | label 165 | 128 128 255 166 | 230 230 230 167 | 168 | 169 | RGB 170 | label 171 | UNSIGNEDDECRADIX 172 | 173 | g 174 | g 175 | 176 | 177 | r 178 | r 179 | 180 | 181 | b 182 | b 183 | 184 | 185 | 186 | i 187 | i 188 | 189 | 190 | csync 191 | csync 192 | 193 | 194 | Contention handler 195 | label 196 | 128 128 255 197 | 230 230 230 198 | 199 | 200 | CLKContention 201 | CLKContention 202 | 203 | 204 | Nor1 205 | Nor1 206 | 207 | 208 | Nor2 209 | Nor2 210 | 211 | 212 | CPU 213 | label 214 | 128 128 255 215 | 230 230 230 216 | 217 | 218 | clk7 219 | clk7 220 | 221 | 222 | clk 223 | clk 224 | 225 | 226 | a[15:0] 227 | a[15:0] 228 | HEXRADIX 229 | 230 | 231 | mreq_n 232 | mreq_n 233 | 234 | 235 | iorq_n 236 | iorq_n 237 | 238 | 239 | wr_n 240 | wr_n 241 | 242 | 243 | d[7:0] 244 | d[7:0] 245 | UNSIGNEDDECRADIX 246 | 247 | 248 | -------------------------------------------------------------------------------- /fpga_version/rtl/ula_with_timex_hicolor_support_and_ulaplus.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar. rodriguj@atc.us.es 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ZX Spectrum 8 | // Module Name: ula 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 1.00 - File Created 18 | // Additional Comments: GPL License policies apply to the contents of this file. 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ula( 26 | input clk14, // 14MHz master clock 27 | input reset, // to reset the ULA to normal color mode. 28 | // CPU interfacing 29 | input [15:0] a, // Address bus from CPU (not all lines are used) 30 | input [7:0] din, // Input data bus from CPU 31 | output [7:0] dout, // Output data bus to CPU 32 | input mreq_n, // MREQ from CPU 33 | input iorq_n, // IORQ from CPU 34 | input rd_n, // RD from CPU 35 | input wr_n, // WR from CPU 36 | input rfsh_n, // RFSH from CPU 37 | output clkcpu, // CLK to CPU 38 | output msk_int_n, // Vertical retrace interrupt, to CPU 39 | // VRAM interfacing 40 | output [13:0] va, // Address bus to VRAM (16K) 41 | input [7:0] vramdout,// Data from VRAM to ULA/CPU 42 | output [7:0] vramdin,// Data from CPU to VRAM 43 | output vramoe, // 44 | output vramcs, // Control signals for VRAM 45 | output vramwe, // 46 | // ULA I/O 47 | input ear, // 48 | output mic, // I/O ports 49 | output spk, // 50 | output [7:0] kbrows, // Keyboard rows 51 | input [4:0] kbcolumns, // Keyboard columns 52 | // Video output 53 | output r, // 54 | output g, // RGB TTL signal 55 | output b, // with separate bright 56 | output i, // and composite sync 57 | output [7:0] rgbulaplus, // 8-bit RGB value for current pixel, ULA+ 58 | output ulaplus_enabled, // =1 if ULAPlus enabled. To help selecting the right outputs to the RGB DAC 59 | output csync // 60 | ); 61 | 62 | reg [2:0] BorderColor = 3'b100; 63 | reg TimexHiColorMode = 0; 64 | 65 | reg ULAPlusConfig = 0; // bit 0 of reg.64 66 | reg [7:0] ULAPlusAddrReg = 0; // ULA+ register address, BF3Bh port. 67 | assign ulaplus_enabled = ULAPlusConfig; 68 | wire addrportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b10); // port BF3Bh 69 | wire dataportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b11); // port FF3Bh 70 | wire cpu_writes_palette = dataportsel && !wr_n && (ULAPlusAddrReg[7:6]==2'b00); //=1 if CPU wants to write a palette entry to RAM 71 | reg [5:0] paletteaddr; // address bus of palette RAM 72 | wire [7:0] palettedout; // data out port of palette RAM 73 | reg palettewe; // WE signal of palette RAM (palette RAM is always selected and output enabled) 74 | 75 | ram64bytes palette ( 76 | .clk(clk14), // only for write operations. Read operations are asynchronous 77 | .a(paletteaddr), 78 | .din(din), 79 | .dout(palettedout), 80 | .we(palettewe) // RAM is written if WE is enabled at the rising edge of clk 81 | ); 82 | 83 | // Pixel clock 84 | reg clk7 = 0; 85 | always @(posedge clk14) 86 | clk7 <= !clk7; 87 | 88 | // Horizontal counter 89 | reg [8:0] hc = 0; 90 | always @(posedge clk7) begin 91 | if (hc==447) 92 | hc <= 0; 93 | else 94 | hc <= hc + 1; 95 | end 96 | 97 | // Vertical counter 98 | reg [8:0] vc = 0; 99 | always @(posedge clk7) begin 100 | if (hc==447) begin 101 | if (vc == 311) 102 | vc <= 0; 103 | else 104 | vc <= vc + 1; 105 | end 106 | end 107 | 108 | // HBlank generation 109 | reg HBlank_n = 1; 110 | always @(negedge clk7) begin 111 | if (`cyclestart(hc,320)) 112 | HBlank_n <= 0; 113 | else if (`cycleend(hc,415)) 114 | HBlank_n <= 1; 115 | end 116 | 117 | // HSync generation (6C ULA version) 118 | reg HSync_n = 1; 119 | always @(negedge clk7) begin 120 | if (`cyclestart(hc,344)) 121 | HSync_n <= 0; 122 | else if (`cycleend(hc,375)) 123 | HSync_n <= 1; 124 | end 125 | 126 | // VBlank generation 127 | reg VBlank_n = 1; 128 | always @(negedge clk7) begin 129 | if (`cyclestart(vc,248)) 130 | VBlank_n <= 0; 131 | else if (`cycleend(vc,255)) 132 | VBlank_n <= 1; 133 | end 134 | 135 | // VSync generation (PAL) 136 | reg VSync_n = 1; 137 | always @(negedge clk7) begin 138 | if (`cyclestart(vc,248)) 139 | VSync_n <= 0; 140 | else if (`cycleend(vc,251)) 141 | VSync_n <= 1; 142 | end 143 | 144 | // INT generation 145 | reg INT_n = 1; 146 | assign msk_int_n = INT_n; 147 | always @(negedge clk7) begin 148 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 149 | INT_n <= 0; 150 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 151 | INT_n <= 1; 152 | end 153 | 154 | // Border control signal (=0 when we're not displaying paper/ink pixels) 155 | reg Border_n = 1; 156 | always @(negedge clk7) begin 157 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 158 | Border_n <= 0; 159 | else 160 | Border_n <= 1; 161 | end 162 | 163 | // VidEN generation (delaying Border 8 clocks) 164 | reg VidEN_n = 1; 165 | always @(negedge clk7) begin 166 | if (hc[3]) 167 | VidEN_n <= !Border_n; 168 | end 169 | 170 | // DataLatch generation (posedge to capture data from memory) 171 | reg DataLatch_n = 1; 172 | always @(negedge clk7) begin 173 | if (hc[0] & hc[1] & Border_n & hc[3]) 174 | DataLatch_n <= 0; 175 | else 176 | DataLatch_n <= 1; 177 | end 178 | 179 | // AttrLatch generation (posedge to capture data from memory) 180 | reg AttrLatch_n = 1; 181 | always @(negedge clk7) begin 182 | if (hc[0] & !hc[1] & Border_n & hc[3]) 183 | AttrLatch_n <= 0; 184 | else 185 | AttrLatch_n <= 1; 186 | end 187 | 188 | // SLoad generation (negedge to load shift register) 189 | reg SLoad = 0; 190 | always @(negedge clk7) begin 191 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 192 | SLoad <= 1; 193 | else 194 | SLoad <= 0; 195 | end 196 | 197 | // AOLatch generation (negedge to update attr output latch) 198 | reg AOLatch_n = 1; 199 | always @(negedge clk7) begin 200 | if (hc[0] & !hc[1] & hc[2]) 201 | AOLatch_n <= 0; 202 | else 203 | AOLatch_n <= 1; 204 | end 205 | 206 | // First buffer for bitmap 207 | reg [7:0] BitmapReg = 0; 208 | always @(negedge DataLatch_n) begin 209 | BitmapReg <= vramdout; 210 | end 211 | 212 | // Shift register (second bitmap register) 213 | reg [7:0] SRegister = 0; 214 | always @(negedge clk7) begin 215 | if (SLoad) 216 | SRegister <= BitmapReg; 217 | else 218 | SRegister <= {SRegister[6:0],1'b0}; 219 | end 220 | 221 | // First buffer for attribute 222 | reg [7:0] AttrReg = 0; 223 | always @(negedge AttrLatch_n) begin 224 | AttrReg <= vramdout; 225 | end 226 | 227 | // Second buffer for attribute 228 | reg [7:0] AttrOut = 0; 229 | always @(negedge AOLatch_n) begin 230 | if (!VidEN_n) 231 | AttrOut <= AttrReg; 232 | else 233 | AttrOut <= {2'b00,BorderColor,BorderColor}; 234 | end 235 | 236 | // Flash counter and pixel generation 237 | reg [4:0] FlashCnt = 0; 238 | always @(negedge VSync_n) begin 239 | FlashCnt <= FlashCnt + 1; 240 | end 241 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 242 | 243 | // RGB generation 244 | reg rI,rG,rR,rB; 245 | assign r = rR; 246 | assign g = rG; 247 | assign b = rB; 248 | assign i = rI; 249 | always @(*) begin 250 | if (HBlank_n && VBlank_n) 251 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 252 | else 253 | {rI,rG,rR,rB} = 4'b0000; 254 | end 255 | 256 | //CSync generation 257 | assign csync = HSync_n & VSync_n; 258 | 259 | // VRAM address and control line generation 260 | reg [13:0] rVA = 0; 261 | reg rVCS = 0; 262 | reg rVOE = 0; 263 | reg rVWE = 0; 264 | assign va = rVA; 265 | assign vramcs = rVCS; 266 | assign vramoe = rVOE; 267 | assign vramwe = rVWE; 268 | // Latches to hold delayed versions of V and H counters 269 | reg [8:0] v = 0; 270 | reg [8:0] c = 0; 271 | // Address and control line multiplexor ULA/CPU 272 | always @(negedge clk7) begin 273 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 274 | c <= hc; 275 | v <= vc; 276 | end 277 | end 278 | // Address and control line multiplexor ULA/CPU 279 | always @(*) begin 280 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present attribute address to VRAM 281 | rVA = (TimexHiColorMode)? {1'b1,v[7:6],v[2:0],v[5:3],c[7:3]} : // (cycles 9 and 13 load attr byte). 282 | {4'b0110,v[7:3],c[7:3]}; // Attribute address depends upon the mode selected 283 | rVCS = 1; 284 | rVOE = !hc[0]; 285 | rVWE = 0; 286 | end 287 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present display address to VRAM 288 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 11 and 15 load display byte) 289 | rVCS = 1; 290 | rVOE = !hc[0]; 291 | rVWE = 0; 292 | end 293 | else if (Border_n && hc[3:0]==4'b0000) begin 294 | rVA = a[13:0]; 295 | rVCS = 0; 296 | rVOE = 0; 297 | rVWE = 0; 298 | end 299 | else begin // when VRAM is not in use by ULA, give it to CPU 300 | rVA = a[13:0]; 301 | rVCS = !a[15] & a[14] & !mreq_n; 302 | rVOE = !rd_n; 303 | rVWE = !wr_n; 304 | end 305 | end 306 | 307 | // ULA+ : palette RAM address and control bus multiplexing 308 | always @(*) begin 309 | if (Border_n && (hc[3:0]==10 || hc[3:0]==14)) begin // present address of paper to palette RAM 310 | palettewe = 0; 311 | paletteaddr = { AttrReg[7:6],1'b1,AttrReg[5:3] }; 312 | end 313 | else if (Border_n && (hc[3:0]==11 || hc[3:0]==15)) begin // present address of ink to palette RAM 314 | palettewe = 0; 315 | paletteaddr = { AttrReg[7:6],1'b0,AttrReg[2:0] }; 316 | end 317 | else if (dataportsel) begin // if CPU requests access, give it palette control 318 | paletteaddr = ULAPlusAddrReg[5:0]; 319 | palettewe = cpu_writes_palette; 320 | end 321 | else begin // if palette RAM is not being used to display pixels, and the CPU doesn't need it, put the border color address 322 | palettewe = 0; // blocking assignment, so we will first deassert WE at palette RAM... 323 | paletteaddr = {3'b001, BorderColor}; // ... then, we can change the palette RAM address 324 | end 325 | end 326 | 327 | //ULA+ : palette reading and attribute generation 328 | // First buffers for paper and ink 329 | reg [7:0] ULAPlusPaper = 0; 330 | reg [7:0] ULAPlusInk = 0; 331 | reg [7:0] ULAPlusBorder = 0; 332 | wire ULAPlusPixel = SRegister[7]; 333 | always @(negedge clk14) begin 334 | if (Border_n && (hc[3:0]==10 || hc[3:0]==14) && !clk7) // this happens 1/2 clk7 after address is settled 335 | ULAPlusPaper <= palettedout; 336 | else if (Border_n && (hc[3:0]==11 || hc[3:0]==15) && !clk7) // this happens 1/2 clk7 after address is settled 337 | ULAPlusInk <= palettedout; 338 | else if (hc[3:0]==12 && !dataportsel) // On cycle 12, palette RAM is not used to retrieve ink/paper color. If CPU is not reclaiming it... 339 | ULAPlusBorder <= palettedout; //... take the chance to update the BorderColor register by reading the palette RAM. The address 340 | end // presented at the palette RAM address bus will be 001BBB, where BBB is the border color code. 341 | // Second buffers for paper and ink 342 | reg [7:0] ULAPlusPaperOut = 0; 343 | reg [7:0] ULAPlusInkOut = 0; 344 | always @(negedge AOLatch_n) begin 345 | if (!VidEN_n) begin // if it's "paper time", load output buffers with current ink and paper color 346 | ULAPlusPaperOut <= ULAPlusPaper; 347 | ULAPlusInkOut <= ULAPlusInk; 348 | end 349 | else begin // if not, it's "border/blanking time", so load output buffers with current border color 350 | ULAPlusPaperOut <= ULAPlusBorder; 351 | ULAPlusInkOut <= ULAPlusBorder; 352 | end 353 | end 354 | // ULA+ : final RGB generation depending on pixel value and blanking period. 355 | reg [7:0] rRGBULAPlus; 356 | assign rgbulaplus = rRGBULAPlus; 357 | always @(*) begin 358 | if (HBlank_n && VBlank_n) 359 | rRGBULAPlus = (ULAPlusPixel)? ULAPlusInkOut : ULAPlusPaperOut; 360 | else 361 | rRGBULAPlus = 8'h00; 362 | end 363 | 364 | // CPU contention 365 | reg CPUClk = 0; 366 | assign clkcpu = CPUClk; 367 | reg ioreqtw3 = 0; 368 | reg mreqt23 = 0; 369 | wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel; 370 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 371 | (~(~a[15] | ~ioreq_n)) | 372 | (~(hc[2] | hc[3])) | 373 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 374 | wire Nor2 = (~(hc[2] | hc[3])) | 375 | ~Border_n | 376 | ~CPUClk | 377 | ioreq_n | 378 | ~ioreqtw3; 379 | wire CLKContention = ~Nor1 | ~Nor2; 380 | 381 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 382 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 383 | CPUClk <= 0; 384 | else 385 | CPUClk <= 1; 386 | end 387 | always @(posedge CPUClk) begin 388 | ioreqtw3 <= ioreq_n; 389 | mreqt23 <= mreq_n; 390 | end 391 | 392 | // ULA+ : palette management 393 | always @(posedge clk7 or posedge reset) begin 394 | if (reset) 395 | ULAPlusConfig <= 0; 396 | else begin 397 | if (addrportsel && !wr_n) 398 | ULAPlusAddrReg <= din; 399 | else if (dataportsel && !wr_n && ULAPlusAddrReg[7:6]==2'b01) 400 | ULAPlusConfig <= din[0]; 401 | end 402 | end 403 | 404 | // ULA-CPU interface 405 | assign dout = (!a[15] && a[14] && !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly 406 | (!iorq_n && !a[0])? {1'b1,ear,1'b1,kbcolumns} : // CPU reads keyboard and EAR state 407 | (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported. 408 | (addrportsel && !rd_n)? ULAPlusAddrReg : // ULA+ addr register 409 | (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b01)? {7'b0000000, ULAPlusConfig} : 410 | (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b00)? palettedout : 411 | (Border_n)? AttrReg : // to emulate 412 | 8'hFF; // port FF (well, cannot be actually FF anymore) 413 | assign vramdin = din; // The CPU doesn't need to share the memory input data bus with the ULA 414 | assign kbrows = {a[11]? 1'bz : 1'b0, // high impedance or 0, as if diodes were been placed in between 415 | a[10]? 1'bz : 1'b0, // if the keyboard matrix is to be implemented within the FPGA, then 416 | a[9]? 1'bz : 1'b0, // there's no need to do this. 417 | a[12]? 1'bz : 1'b0, 418 | a[13]? 1'bz : 1'b0, 419 | a[8]? 1'bz : 1'b0, 420 | a[14]? 1'bz : 1'b0, 421 | a[15]? 1'bz : 1'b0 }; 422 | reg rMic = 0; 423 | reg rSpk = 0; 424 | assign mic = rMic; 425 | assign spk = rSpk; 426 | always @(negedge clk7 or posedge reset) begin 427 | if (reset) 428 | TimexHiColorMode <= 0; 429 | else if (!iorq_n && a[7:0]==8'hFF && !wr_n) 430 | TimexHiColorMode <= din[1]; 431 | else if (!iorq_n & !a[0] & !wr_n) 432 | {rSpk,rMic,BorderColor} <= din[5:0]; 433 | end 434 | endmodule 435 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/ula_with_timex_hicolor_support_and_ulaplus.v: -------------------------------------------------------------------------------- 1 | `timescale 1ns / 1ps 2 | ////////////////////////////////////////////////////////////////////////////////// 3 | // Company: Dept. Architecture and Computing Technology. University of Seville 4 | // Engineer: Miguel Angel Rodriguez Jodar. rodriguj@atc.us.es 5 | // 6 | // Create Date: 19:13:39 4-Apr-2012 7 | // Design Name: ZX Spectrum 8 | // Module Name: ula 9 | // Project Name: 10 | // Target Devices: 11 | // Tool versions: 12 | // Description: 13 | // 14 | // Dependencies: 15 | // 16 | // Revision: 17 | // Revision 1.00 - File Created 18 | // Additional Comments: GPL License policies apply to the contents of this file. 19 | // 20 | ////////////////////////////////////////////////////////////////////////////////// 21 | 22 | `define cyclestart(a,b) ((a)==(b)) 23 | `define cycleend(a,b) ((a)==(b+1)) 24 | 25 | module ulaplus ( 26 | input clk14, // 14MHz master clock 27 | input reset, // to reset the ULA to normal color mode. 28 | // CPU interfacing 29 | input [15:0] a, // Address bus from CPU (not all lines are used) 30 | input [7:0] din, // Input data bus from CPU 31 | output [7:0] dout, // Output data bus to CPU 32 | input mreq_n, // MREQ from CPU 33 | input iorq_n, // IORQ from CPU 34 | input rd_n, // RD from CPU 35 | input wr_n, // WR from CPU 36 | input rfsh_n, // RFSH from CPU 37 | output clkcpu, // CLK to CPU 38 | output msk_int_n, // Vertical retrace interrupt, to CPU 39 | // VRAM interfacing 40 | output [13:0] va, // Address bus to VRAM (16K) 41 | input [7:0] vramdout,// Data from VRAM to ULA/CPU 42 | output [7:0] vramdin,// Data from CPU to VRAM 43 | output vramoe, // 44 | output vramcs, // Control signals for VRAM 45 | output vramwe, // 46 | // ULA I/O 47 | input ear, // 48 | output mic, // I/O ports 49 | output spk, // 50 | output [7:0] kbrows, // Keyboard rows 51 | input [4:0] kbcolumns, // Keyboard columns 52 | // Video output 53 | output r, // 54 | output g, // RGB TTL signal 55 | output b, // with separate bright 56 | output i, // and composite sync 57 | output [7:0] rgbulaplus, // 8-bit RGB value for current pixel, ULA+ 58 | output ulaplus_enabled, // =1 if ULAPlus enabled. To help selecting the right outputs to the RGB DAC 59 | output csync // 60 | ); 61 | 62 | reg [2:0] BorderColor = 3'b100; 63 | reg TimexHiColorMode = 0; 64 | 65 | reg ULAPlusConfig = 0; // bit 0 of reg.64 66 | reg [7:0] ULAPlusAddrReg = 0; // ULA+ register address, BF3Bh port. 67 | assign ulaplus_enabled = ULAPlusConfig; 68 | wire addrportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b10); // port BF3Bh 69 | wire dataportsel = !iorq_n && a[0] && !a[2] && (a[7:6]==2'b00) && (a[15:14]==2'b11); // port FF3Bh 70 | wire cpu_writes_palette = dataportsel && !wr_n && (ULAPlusAddrReg[7:6]==2'b00); //=1 if CPU wants to write a palette entry to RAM 71 | reg [5:0] paletteaddr; // address bus of palette RAM 72 | wire [7:0] palettedout; // data out port of palette RAM 73 | reg palettewe; // WE signal of palette RAM (palette RAM is always selected and output enabled) 74 | 75 | ram64bytes palette ( 76 | .clk(clk14), // only for write operations. Read operations are asynchronous 77 | .a(paletteaddr), 78 | .din(din), 79 | .dout(palettedout), 80 | .we(palettewe) // RAM is written if WE is enabled at the rising edge of clk 81 | ); 82 | 83 | // Pixel clock 84 | reg clk7 = 0; 85 | always @(posedge clk14) 86 | clk7 <= !clk7; 87 | 88 | // Horizontal counter 89 | reg [8:0] hc = 0; 90 | always @(posedge clk7) begin 91 | if (hc==447) 92 | hc <= 0; 93 | else 94 | hc <= hc + 1; 95 | end 96 | 97 | // Vertical counter 98 | reg [8:0] vc = 0; 99 | always @(posedge clk7) begin 100 | if (hc==447) begin 101 | if (vc == 311) 102 | vc <= 0; 103 | else 104 | vc <= vc + 1; 105 | end 106 | end 107 | 108 | // HBlank generation 109 | reg HBlank_n = 1; 110 | always @(negedge clk7) begin 111 | if (`cyclestart(hc,320)) 112 | HBlank_n <= 0; 113 | else if (`cycleend(hc,415)) 114 | HBlank_n <= 1; 115 | end 116 | 117 | // HSync generation (6C ULA version) 118 | reg HSync_n = 1; 119 | always @(negedge clk7) begin 120 | if (`cyclestart(hc,344)) 121 | HSync_n <= 0; 122 | else if (`cycleend(hc,375)) 123 | HSync_n <= 1; 124 | end 125 | 126 | // VBlank generation 127 | reg VBlank_n = 1; 128 | always @(negedge clk7) begin 129 | if (`cyclestart(vc,248)) 130 | VBlank_n <= 0; 131 | else if (`cycleend(vc,255)) 132 | VBlank_n <= 1; 133 | end 134 | 135 | // VSync generation (PAL) 136 | reg VSync_n = 1; 137 | always @(negedge clk7) begin 138 | if (`cyclestart(vc,248)) 139 | VSync_n <= 0; 140 | else if (`cycleend(vc,251)) 141 | VSync_n <= 1; 142 | end 143 | 144 | // INT generation 145 | reg INT_n = 1; 146 | assign msk_int_n = INT_n; 147 | always @(negedge clk7) begin 148 | if (`cyclestart(vc,248) && `cyclestart(hc,0)) 149 | INT_n <= 0; 150 | else if (`cyclestart(vc,248) && `cycleend(hc,31)) 151 | INT_n <= 1; 152 | end 153 | 154 | // Border control signal (=0 when we're not displaying paper/ink pixels) 155 | reg Border_n = 1; 156 | always @(negedge clk7) begin 157 | if ( (vc[7] & vc[6]) | vc[8] | hc[8]) 158 | Border_n <= 0; 159 | else 160 | Border_n <= 1; 161 | end 162 | 163 | // VidEN generation (delaying Border 8 clocks) 164 | reg VidEN_n = 1; 165 | always @(negedge clk7) begin 166 | if (hc[3]) 167 | VidEN_n <= !Border_n; 168 | end 169 | 170 | // DataLatch generation (posedge to capture data from memory) 171 | reg DataLatch_n = 1; 172 | always @(negedge clk7) begin 173 | if (hc[0] & hc[1] & Border_n & hc[3]) 174 | DataLatch_n <= 0; 175 | else 176 | DataLatch_n <= 1; 177 | end 178 | 179 | // AttrLatch generation (posedge to capture data from memory) 180 | reg AttrLatch_n = 1; 181 | always @(negedge clk7) begin 182 | if (hc[0] & !hc[1] & Border_n & hc[3]) 183 | AttrLatch_n <= 0; 184 | else 185 | AttrLatch_n <= 1; 186 | end 187 | 188 | // SLoad generation (negedge to load shift register) 189 | reg SLoad = 0; 190 | always @(negedge clk7) begin 191 | if (!hc[0] & !hc[1] & hc[2] & !VidEN_n) 192 | SLoad <= 1; 193 | else 194 | SLoad <= 0; 195 | end 196 | 197 | // AOLatch generation (negedge to update attr output latch) 198 | reg AOLatch_n = 1; 199 | always @(negedge clk7) begin 200 | if (hc[0] & !hc[1] & hc[2]) 201 | AOLatch_n <= 0; 202 | else 203 | AOLatch_n <= 1; 204 | end 205 | 206 | // First buffer for bitmap 207 | reg [7:0] BitmapReg = 0; 208 | always @(negedge DataLatch_n) begin 209 | BitmapReg <= vramdout; 210 | end 211 | 212 | // Shift register (second bitmap register) 213 | reg [7:0] SRegister = 0; 214 | always @(negedge clk7) begin 215 | if (SLoad) 216 | SRegister <= BitmapReg; 217 | else 218 | SRegister <= {SRegister[6:0],1'b0}; 219 | end 220 | 221 | // First buffer for attribute 222 | reg [7:0] AttrReg = 0; 223 | always @(negedge AttrLatch_n) begin 224 | AttrReg <= vramdout; 225 | end 226 | 227 | // Second buffer for attribute 228 | reg [7:0] AttrOut = 0; 229 | always @(negedge AOLatch_n) begin 230 | if (!VidEN_n) 231 | AttrOut <= AttrReg; 232 | else 233 | AttrOut <= {2'b00,BorderColor,BorderColor}; 234 | end 235 | 236 | // Flash counter and pixel generation 237 | reg [4:0] FlashCnt = 0; 238 | always @(negedge VSync_n) begin 239 | FlashCnt <= FlashCnt + 1; 240 | end 241 | wire Pixel = SRegister[7] ^ (AttrOut[7] & FlashCnt[4]); 242 | 243 | // RGB generation 244 | reg rI,rG,rR,rB; 245 | assign r = rR; 246 | assign g = rG; 247 | assign b = rB; 248 | assign i = rI; 249 | always @(*) begin 250 | if (HBlank_n && VBlank_n) 251 | {rI,rG,rR,rB} = (Pixel)? {AttrOut[6],AttrOut[2:0]} : {AttrOut[6],AttrOut[5:3]}; 252 | else 253 | {rI,rG,rR,rB} = 4'b0000; 254 | end 255 | 256 | //CSync generation 257 | assign csync = HSync_n & VSync_n; 258 | 259 | // VRAM address and control line generation 260 | reg [13:0] rVA = 0; 261 | reg rVCS = 0; 262 | reg rVOE = 0; 263 | reg rVWE = 0; 264 | assign va = rVA; 265 | assign vramcs = rVCS; 266 | assign vramoe = rVOE; 267 | assign vramwe = rVWE; 268 | // Latches to hold delayed versions of V and H counters 269 | reg [8:0] v = 0; 270 | reg [8:0] c = 0; 271 | // Address and control line multiplexor ULA/CPU 272 | always @(negedge clk7) begin 273 | if (Border_n && (hc[3:0]==4'b0111 || hc[3:0]==4'b1011)) begin // cycles 7 and 11: load V and C from VC and HC 274 | c <= hc; 275 | v <= vc; 276 | end 277 | end 278 | // Address and control line multiplexor ULA/CPU 279 | always @(*) begin 280 | if (Border_n && (hc[3:0]==4'b1000 || hc[3:0]==4'b1001 || hc[3:0]==4'b1100 || hc[3:0]==4'b1101)) begin // cycles 8 and 12: present attribute address to VRAM 281 | rVA = (TimexHiColorMode)? {1'b1,v[7:6],v[2:0],v[5:3],c[7:3]} : // (cycles 9 and 13 load attr byte). 282 | {4'b0110,v[7:3],c[7:3]}; // Attribute address depends upon the mode selected 283 | rVCS = 1; 284 | rVOE = !hc[0]; 285 | rVWE = 0; 286 | end 287 | else if (Border_n && (hc[3:0]==4'b1010 || hc[3:0]==4'b1011 || hc[3:0]==4'b1110 || hc[3:0]==4'b1111)) begin // cycles 10 and 14: present display address to VRAM 288 | rVA = {1'b0,v[7:6],v[2:0],v[5:3],c[7:3]}; // (cycles 11 and 15 load display byte) 289 | rVCS = 1; 290 | rVOE = !hc[0]; 291 | rVWE = 0; 292 | end 293 | else if (Border_n && hc[3:0]==4'b0000) begin 294 | rVA = a[13:0]; 295 | rVCS = 0; 296 | rVOE = 0; 297 | rVWE = 0; 298 | end 299 | else begin // when VRAM is not in use by ULA, give it to CPU 300 | rVA = a[13:0]; 301 | rVCS = !a[15] & a[14] & !mreq_n; 302 | rVOE = !rd_n; 303 | rVWE = !wr_n; 304 | end 305 | end 306 | 307 | // ULA+ : palette RAM address and control bus multiplexing 308 | always @(*) begin 309 | if (Border_n && (hc[3:0]==10 || hc[3:0]==14)) begin // present address of paper to palette RAM 310 | palettewe = 0; 311 | paletteaddr = { AttrReg[7:6],1'b1,AttrReg[5:3] }; 312 | end 313 | else if (Border_n && (hc[3:0]==11 || hc[3:0]==15)) begin // present address of ink to palette RAM 314 | palettewe = 0; 315 | paletteaddr = { AttrReg[7:6],1'b0,AttrReg[2:0] }; 316 | end 317 | else if (dataportsel) begin // if CPU requests access, give it palette control 318 | paletteaddr = ULAPlusAddrReg[5:0]; 319 | palettewe = cpu_writes_palette; 320 | end 321 | else begin // if palette RAM is not being used to display pixels, and the CPU doesn't need it, put the border color address 322 | palettewe = 0; // blocking assignment, so we will first deassert WE at palette RAM... 323 | paletteaddr = {3'b001, BorderColor}; // ... then, we can change the palette RAM address 324 | end 325 | end 326 | 327 | //ULA+ : palette reading and attribute generation 328 | // First buffers for paper and ink 329 | reg [7:0] ULAPlusPaper = 0; 330 | reg [7:0] ULAPlusInk = 0; 331 | reg [7:0] ULAPlusBorder = 0; 332 | wire ULAPlusPixel = SRegister[7]; 333 | always @(negedge clk14) begin 334 | if (Border_n && (hc[3:0]==10 || hc[3:0]==14) && !clk7) // this happens 1/2 clk7 after address is settled 335 | ULAPlusPaper <= palettedout; 336 | else if (Border_n && (hc[3:0]==11 || hc[3:0]==15) && !clk7) // this happens 1/2 clk7 after address is settled 337 | ULAPlusInk <= palettedout; 338 | else if (hc[3:0]==12 && !dataportsel) // On cycle 12, palette RAM is not used to retrieve ink/paper color. If CPU is not reclaiming it... 339 | ULAPlusBorder <= palettedout; //... take the chance to update the BorderColor register by reading the palette RAM. The address 340 | end // presented at the palette RAM address bus will be 001BBB, where BBB is the border color code. 341 | // Second buffers for paper and ink 342 | reg [7:0] ULAPlusPaperOut = 0; 343 | reg [7:0] ULAPlusInkOut = 0; 344 | always @(negedge AOLatch_n) begin 345 | if (!VidEN_n) begin // if it's "paper time", load output buffers with current ink and paper color 346 | ULAPlusPaperOut <= ULAPlusPaper; 347 | ULAPlusInkOut <= ULAPlusInk; 348 | end 349 | else begin // if not, it's "border/blanking time", so load output buffers with current border color 350 | ULAPlusPaperOut <= ULAPlusBorder; 351 | ULAPlusInkOut <= ULAPlusBorder; 352 | end 353 | end 354 | // ULA+ : final RGB generation depending on pixel value and blanking period. 355 | reg [7:0] rRGBULAPlus; 356 | assign rgbulaplus = rRGBULAPlus; 357 | always @(*) begin 358 | if (HBlank_n && VBlank_n) 359 | rRGBULAPlus = (ULAPlusPixel)? ULAPlusInkOut : ULAPlusPaperOut; 360 | else 361 | rRGBULAPlus = 8'h00; 362 | end 363 | 364 | // CPU contention 365 | reg CPUClk = 0; 366 | assign clkcpu = CPUClk; 367 | reg ioreqtw3 = 0; 368 | reg mreqt23 = 0; 369 | wire ioreq_n = (a[0] | iorq_n) & ~dataportsel & ~addrportsel; 370 | wire Nor1 = (~(a[14] | ~ioreq_n)) | 371 | (~(~a[15] | ~ioreq_n)) | 372 | (~(hc[2] | hc[3])) | 373 | (~Border_n | ~ioreqtw3 | ~CPUClk | ~mreqt23); 374 | wire Nor2 = (~(hc[2] | hc[3])) | 375 | ~Border_n | 376 | ~CPUClk | 377 | ioreq_n | 378 | ~ioreqtw3; 379 | wire CLKContention = ~Nor1 | ~Nor2; 380 | 381 | always @(posedge clk7) begin // change clk7 by clk14 for 7MHz CPU clock operation 382 | if (CPUClk && !CLKContention) // if there's no contention, the clock can go low 383 | CPUClk <= 0; 384 | else 385 | CPUClk <= 1; 386 | end 387 | always @(posedge CPUClk) begin 388 | ioreqtw3 <= ioreq_n; 389 | mreqt23 <= mreq_n; 390 | end 391 | 392 | // ULA+ : palette management 393 | always @(posedge clk7 or posedge reset) begin 394 | if (reset) 395 | ULAPlusConfig <= 0; 396 | else begin 397 | if (addrportsel && !wr_n) 398 | ULAPlusAddrReg <= din; 399 | else if (dataportsel && !wr_n && ULAPlusAddrReg[7:6]==2'b01) 400 | ULAPlusConfig <= din[0]; 401 | end 402 | end 403 | 404 | // ULA-CPU interface 405 | assign dout = (!a[15] && a[14] && !mreq_n)? vramdout : // CPU reads VRAM through ULA as in the +3, not directly 406 | (!iorq_n && !a[0])? {1'b1,ear,1'b1,kbcolumns} : // CPU reads keyboard and EAR state 407 | (!iorq_n && a[7:0]==8'hFF && !rd_n)? {6'b000000,TimexHiColorMode,1'b0} : // Timex hicolor config port. Only bit 1 is reported. 408 | (addrportsel && !rd_n)? ULAPlusAddrReg : // ULA+ addr register 409 | (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b01)? {7'b0000000, ULAPlusConfig} : 410 | (dataportsel && !rd_n && ULAPlusAddrReg[7:6]==2'b00)? palettedout : 411 | (Border_n)? AttrReg : // to emulate 412 | 8'hFF; // port FF (well, cannot be actually FF anymore) 413 | assign vramdin = din; // The CPU doesn't need to share the memory input data bus with the ULA 414 | assign kbrows = {a[11]? 1'bz : 1'b0, // high impedance or 0, as if diodes were been placed in between 415 | a[10]? 1'bz : 1'b0, // if the keyboard matrix is to be implemented within the FPGA, then 416 | a[9]? 1'bz : 1'b0, // there's no need to do this. 417 | a[12]? 1'bz : 1'b0, 418 | a[13]? 1'bz : 1'b0, 419 | a[8]? 1'bz : 1'b0, 420 | a[14]? 1'bz : 1'b0, 421 | a[15]? 1'bz : 1'b0 }; 422 | reg rMic = 0; 423 | reg rSpk = 0; 424 | assign mic = rMic; 425 | assign spk = rSpk; 426 | always @(negedge clk7 or posedge reset) begin 427 | if (reset) 428 | TimexHiColorMode <= 0; 429 | else if (!iorq_n && a[7:0]==8'hFF && !wr_n) 430 | TimexHiColorMode <= din[1]; 431 | else if (!iorq_n & !a[0] & !wr_n) 432 | {rSpk,rMic,BorderColor} <= din[5:0]; 433 | end 434 | endmodule 435 | -------------------------------------------------------------------------------- /fpga_version/ula_test_for_ise_and_isim/isim_test_for_ula.xise: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 |
365 | --------------------------------------------------------------------------------