├── 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 |
--------------------------------------------------------------------------------