Skip to content

Commit 977dd44

Browse files
committed
Enable SHRG Linearization
commit 233df06 Author: Ed Anuff <ed@anuff.com> Date: Sat Mar 2 11:07:04 2024 -0800
1 parent ec88aee commit 977dd44

21 files changed

+12639
-10703
lines changed
Lines changed: 153 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,23 @@
1-
// A2N20v2-SDRAM - Tang Nano 20K SDRAM Version
1+
// 2N20v2-SDRAM - Tang Nano 20K SDRAM implementation of Apple II memory
2+
//
3+
// (c) 2023,2024 Ed Anuff <ed@a2fpga.com>
4+
//
5+
// Permission to use, copy, modify, and/or distribute this software for any
6+
// purpose with or without fee is hereby granted, provided that the above
7+
// copyright notice and this permission notice appear in all copies.
8+
//
9+
// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10+
// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11+
// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12+
// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13+
// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14+
// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15+
// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16+
//
17+
// Description:
218
//
319
// Handle the writing of data to the shadow memory copy of the Apple II's
4-
// memory that is kept in the FPGA's SDRAM.
20+
// memory that is kept in the FPGA's SDRAM. IIgs SHRG memory is in blockram.
521
//
622

723
module apple_memory #(
@@ -17,7 +33,7 @@ module apple_memory #(
1733
input video_bank_i,
1834
input video_rd_i,
1935
output [31:0] video_data_o,
20-
36+
2137
input vgc_active_i,
2238
input [12:0] vgc_address_i,
2339
input vgc_rd_i,
@@ -29,89 +45,77 @@ module apple_memory #(
2945
wire read_strobe = a2bus_if.rw_n && a2bus_if.data_in_strobe;
3046

3147
// II Soft switches
32-
reg switches_ii_r[8];
33-
assign a2mem_if.TEXT_MODE = switches_ii_r[0];
34-
assign a2mem_if.MIXED_MODE = switches_ii_r[1];
35-
assign a2mem_if.PAGE2 = switches_ii_r[2];
36-
assign a2mem_if.HIRES_MODE = switches_ii_r[3];
37-
assign a2mem_if.AN0 = switches_ii_r[4];
38-
assign a2mem_if.AN1 = switches_ii_r[5];
39-
assign a2mem_if.AN2 = switches_ii_r[6];
40-
assign a2mem_if.AN3 = switches_ii_r[7];
48+
reg SWITCHES_II[8];
49+
assign a2mem_if.TEXT_MODE = SWITCHES_II[0];
50+
assign a2mem_if.MIXED_MODE = SWITCHES_II[1];
51+
assign a2mem_if.PAGE2 = SWITCHES_II[2];
52+
assign a2mem_if.HIRES_MODE = SWITCHES_II[3];
53+
assign a2mem_if.AN0 = SWITCHES_II[4];
54+
assign a2mem_if.AN1 = SWITCHES_II[5];
55+
assign a2mem_if.AN2 = SWITCHES_II[6];
56+
assign a2mem_if.AN3 = SWITCHES_II[7];
4157

4258
// ][e auxilary switches
43-
reg switches_iie_r[8];
44-
assign a2mem_if.STORE80 = switches_iie_r[0];
45-
assign a2mem_if.RAMRD = switches_iie_r[1];
46-
assign a2mem_if.RAMWRT = switches_iie_r[2];
47-
assign a2mem_if.CXROM = switches_iie_r[3];
48-
assign a2mem_if.ALTZP = switches_iie_r[4];
49-
assign a2mem_if.C3ROM = switches_iie_r[5];
50-
assign a2mem_if.COL80 = switches_iie_r[6];
51-
assign a2mem_if.ALTCHAR = switches_iie_r[7];
52-
53-
reg [3:0] text_color_r;
54-
reg [3:0] background_color_r;
55-
reg [3:0] border_color_r;
56-
reg monochrome_mode_r;
57-
reg monochrome_dhires_mode_r;
58-
reg shrg_mode_r;
59-
60-
assign a2mem_if.TEXT_COLOR = text_color_r;
61-
assign a2mem_if.BACKGROUND_COLOR = background_color_r;
62-
assign a2mem_if.BORDER_COLOR = border_color_r;
63-
assign a2mem_if.MONOCHROME_MODE = monochrome_mode_r;
64-
assign a2mem_if.MONOCHROME_DHIRES_MODE = monochrome_dhires_mode_r;
65-
assign a2mem_if.SHRG_MODE = shrg_mode_r;
59+
reg SWITCHES_IIE[8];
60+
assign a2mem_if.STORE80 = SWITCHES_IIE[0];
61+
assign a2mem_if.RAMRD = SWITCHES_IIE[1];
62+
assign a2mem_if.RAMWRT = SWITCHES_IIE[2];
63+
assign a2mem_if.CXROM = SWITCHES_IIE[3];
64+
assign a2mem_if.ALTZP = SWITCHES_IIE[4];
65+
assign a2mem_if.C3ROM = SWITCHES_IIE[5];
66+
assign a2mem_if.COL80 = SWITCHES_IIE[6];
67+
assign a2mem_if.ALTCHAR = SWITCHES_IIE[7];
6668

6769
// capture the soft switches
6870
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.system_reset_n) begin
6971
if (!a2bus_if.system_reset_n) begin
70-
switches_ii_r <= '{1'b1, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1};
72+
SWITCHES_II <= '{1'b1, 1'b1, 1'b0, 1'b0, 1'b0, 1'b0, 1'b0, 1'b1};
7173
end else if ((a2bus_if.phi1_posedge) && (a2bus_if.addr[15:4] == 12'hC05) && !a2bus_if.m2sel_n)
72-
switches_ii_r[a2bus_if.addr[3:1]] <= a2bus_if.addr[0];
74+
SWITCHES_II[a2bus_if.addr[3:1]] <= a2bus_if.addr[0];
7375
end
7476

7577
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.system_reset_n) begin
7678
if (!a2bus_if.system_reset_n) begin
77-
switches_iie_r <= '{8{1'b0}};
79+
SWITCHES_IIE <= '{8{1'b0}};
7880
end else if (!a2bus_if.rw_n && (a2bus_if.phi1_posedge) && (a2bus_if.addr[15:4] == 12'hC00) && !a2bus_if.m2sel_n)
79-
switches_iie_r[a2bus_if.addr[3:1]] <= a2bus_if.addr[0];
81+
SWITCHES_IIE[a2bus_if.addr[3:1]] <= a2bus_if.addr[0];
8082
end
8183

8284
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.device_reset_n) begin
8385
if (!a2bus_if.device_reset_n) begin
84-
background_color_r <= 4'h0;
85-
text_color_r <= 4'hF;
86+
a2mem_if.BACKGROUND_COLOR <= 4'h0;
87+
a2mem_if.TEXT_COLOR <= 4'hF;
8688
end else if (write_strobe && (a2bus_if.addr == 16'hC022)) begin
87-
background_color_r <= a2bus_if.data[3:0];
88-
text_color_r <= a2bus_if.data[7:4];
89+
a2mem_if.BACKGROUND_COLOR <= a2bus_if.data[3:0];
90+
a2mem_if.TEXT_COLOR <= a2bus_if.data[7:4];
8991
end
9092
end
9193

9294
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.device_reset_n) begin
9395
if (!a2bus_if.device_reset_n) begin
94-
border_color_r <= 4'h0;
96+
a2mem_if.BORDER_COLOR <= 4'h0;
9597
end else if (write_strobe && (a2bus_if.addr == 16'hC034)) begin
96-
border_color_r <= a2bus_if.data[3:0];
98+
a2mem_if.BORDER_COLOR <= a2bus_if.data[3:0];
9799
end
98100
end
99101

100102
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.system_reset_n) begin
101103
if (!a2bus_if.system_reset_n) begin
102-
monochrome_mode_r <= 1'b0;
104+
a2mem_if.MONOCHROME_MODE <= 1'b0;
103105
end else if (write_strobe && (a2bus_if.addr == 16'hC021)) begin
104-
monochrome_mode_r <= a2bus_if.data[7];
106+
a2mem_if.MONOCHROME_MODE <= a2bus_if.data[7];
105107
end
106108
end
107109

108110
always @(posedge a2bus_if.clk_logic or negedge a2bus_if.system_reset_n) begin
109111
if (!a2bus_if.system_reset_n) begin
110-
monochrome_dhires_mode_r <= 1'b0;
111-
shrg_mode_r <= 1'b0;
112+
a2mem_if.MONOCHROME_DHIRES_MODE <= 1'b0;
113+
a2mem_if.LINEARIZE_MODE <= 1'b0;
114+
a2mem_if.SHRG_MODE <= 1'b0;
112115
end else if (write_strobe && (a2bus_if.addr == 16'hC029)) begin
113-
monochrome_dhires_mode_r <= a2bus_if.data[5];
114-
shrg_mode_r <= a2bus_if.data[7];
116+
a2mem_if.MONOCHROME_DHIRES_MODE <= a2bus_if.data[5];
117+
a2mem_if.LINEARIZE_MODE <= a2bus_if.data[6] | a2bus_if.data[7];
118+
a2mem_if.SHRG_MODE <= a2bus_if.data[7];
115119
end
116120
end
117121

@@ -138,10 +142,9 @@ module apple_memory #(
138142
assign a2mem_if.keycode = keycode_r;
139143
assign a2mem_if.keypress_strobe = keypress_strobe_r;
140144

141-
reg aux_mem_r;
145+
logic aux_mem_r;
142146

143-
always @(*)
144-
begin: aux_ctrl
147+
always_comb begin
145148
aux_mem_r = 1'b0;
146149
if (a2bus_if.addr[15:9] == 7'b0000000 | a2bus_if.addr[15:14] == 2'b11) // Page 00,01,C0-FF
147150
aux_mem_r = a2mem_if.ALTZP;
@@ -166,19 +169,113 @@ module apple_memory #(
166169

167170
wire E1 = aux_mem_r || a2bus_if.m2b0;
168171

172+
wire [31:0] write_word = {a2bus_if.data, a2bus_if.data, a2bus_if.data, a2bus_if.data};
173+
169174
// Apple II bus address ranges
170175
wire bus_addr_0400_0BFF = a2bus_if.addr[15:10] inside {6'b000001, 3'b000010};
171176
wire bus_addr_2000_5FFF = a2bus_if.addr[15:13] inside {3'b001, 3'b010};
172177
wire bus_addr_6000_9FFF = a2bus_if.addr[15:13] inside {3'b011, 3'b100};
173178
wire bus_addr_2000_9FFF = bus_addr_2000_5FFF || bus_addr_6000_9FFF;
174179

180+
wire [14:0] hires_write_offset = 15'({3'(a2bus_if.addr[15:13] - 1'b1), a2bus_if.addr[12:0]});
181+
182+
wire [31:0] hires_data_aux;
183+
184+
function automatic [31:0] interleave_mux(input hi, input [31:0] data_a, input [31:0] data_b);
185+
logic [31:0] result = 0;
186+
if (hi) result = {data_b[31:24], data_a[31:24], data_b[23:16], data_a[23:16]};
187+
else result = {data_b[15:8], data_a[15:8], data_b[7:0], data_a[7:0]};
188+
return result;
189+
endfunction
190+
191+
wire [3:0] hires_byte_enable = 4'(1 << hires_write_offset[1:0]);
192+
193+
// Aux memory bank, linear
194+
195+
// The aux memory bank for hires is 16KB, but but when VGC_MEMORY is set, an additional 16KB is added
196+
197+
// Set up reads and combine ouputs for VGC
198+
199+
wire [11:0] hires_aux_read_offset = vgc_address_i[12:1];
200+
201+
wire [31:0] hires_data_aux_6000_9FFF;
202+
203+
assign vgc_data_o = vgc_active_i ? interleave_mux(vgc_address_i[0], hires_data_aux, hires_data_aux_6000_9FFF) : 32'b0;
204+
205+
// Set up writes
206+
207+
logic write_enable_aux_2000_5FFF;
208+
logic write_enable_aux_6000_9FFF;
209+
logic [11:0] write_offset_aux_2000_5FFF;
210+
logic [11:0] write_offset_aux_6000_9FFF;
211+
logic [3:0] hires_byte_enable_aux_2000_5FFF;
212+
logic [3:0] hires_byte_enable_aux_6000_9FFF;
213+
214+
always_comb begin
215+
write_enable_aux_2000_5FFF = 1'b0;
216+
write_offset_aux_2000_5FFF = 12'b0;
217+
hires_byte_enable_aux_2000_5FFF = 4'b0;
218+
219+
write_enable_aux_6000_9FFF = 1'b0;
220+
write_offset_aux_6000_9FFF = 12'b0;
221+
hires_byte_enable_aux_6000_9FFF = 4'b0;
222+
223+
if (a2mem_if.LINEARIZE_MODE) begin
224+
write_enable_aux_2000_5FFF = write_strobe && bus_addr_2000_9FFF && E1;
225+
write_offset_aux_2000_5FFF = hires_write_offset[14:3];
226+
hires_byte_enable_aux_2000_5FFF = hires_write_offset[0] ? 4'b0 : 4'(1 << hires_write_offset[2:1]);
227+
228+
write_enable_aux_6000_9FFF = write_strobe && bus_addr_2000_9FFF && E1;
229+
write_offset_aux_6000_9FFF = hires_write_offset[14:3];
230+
hires_byte_enable_aux_6000_9FFF = hires_write_offset[0] ? 4'(1 << hires_write_offset[2:1]) : 4'b0;
231+
232+
end else begin
233+
if (bus_addr_2000_5FFF) begin
234+
write_enable_aux_2000_5FFF = write_strobe && bus_addr_2000_5FFF && E1;
235+
write_offset_aux_2000_5FFF = hires_write_offset[13:2];
236+
hires_byte_enable_aux_2000_5FFF = hires_byte_enable;
237+
end else if (bus_addr_6000_9FFF) begin
238+
write_enable_aux_6000_9FFF = write_strobe && bus_addr_6000_9FFF && E1;
239+
write_offset_aux_6000_9FFF = hires_write_offset[13:2];
240+
hires_byte_enable_aux_6000_9FFF = hires_byte_enable;
241+
end
242+
end
243+
244+
end
245+
246+
sdpram32 #(
247+
.ADDR_WIDTH(12)
248+
) hires_aux_2000_5FFF (
249+
.clk(a2bus_if.clk_logic),
250+
.write_addr(write_offset_aux_2000_5FFF),
251+
.write_data(write_word),
252+
.write_enable(write_enable_aux_2000_5FFF),
253+
.byte_enable(hires_byte_enable_aux_2000_5FFF),
254+
.read_addr(hires_aux_read_offset),
255+
.read_enable(1'b1),
256+
.read_data(hires_data_aux)
257+
);
258+
259+
sdpram32 #(
260+
.ADDR_WIDTH(12)
261+
) hires_aux_6000_9FFF (
262+
.clk(a2bus_if.clk_logic),
263+
.write_addr(write_offset_aux_6000_9FFF),
264+
.write_data(write_word),
265+
.write_enable(write_enable_aux_6000_9FFF),
266+
.byte_enable(hires_byte_enable_aux_6000_9FFF),
267+
.read_addr(hires_aux_read_offset),
268+
.read_enable(1'b1),
269+
.read_data(hires_data_aux_6000_9FFF)
270+
);
271+
272+
// SDRAM interace
273+
175274
wire write_en = !a2bus_if.rw_n &&
176275
a2bus_if.data_in_strobe &&
177276
(SHADOW_ALL_MEMORY || bus_addr_2000_5FFF || bus_addr_0400_0BFF) &&
178277
!a2bus_if.m2sel_n;
179278

180-
wire [31:0] write_word = {a2bus_if.data, a2bus_if.data, a2bus_if.data, a2bus_if.data};
181-
182279
assign main_mem_if.rd = 1'b0;
183280
assign main_mem_if.wr = write_en;
184281
assign main_mem_if.addr = {6'b0, a2bus_if.addr[15:1]};
@@ -192,19 +289,4 @@ module apple_memory #(
192289
assign video_mem_if.byte_en = 4'b1111;
193290
assign video_data_o = video_mem_if.q;
194291

195-
wire [14:0] hires_write_offset = 15'({3'(a2bus_if.addr[15:13] - 1'b1), a2bus_if.addr[12:0]});
196-
197-
sdpram32 #(
198-
.ADDR_WIDTH(13)
199-
) hires_aux (
200-
.clk(a2bus_if.clk_logic),
201-
.write_addr(hires_write_offset[14:2]),
202-
.write_data(write_word),
203-
.write_enable(write_strobe && bus_addr_2000_9FFF && E1),
204-
.byte_enable(4'(1 << hires_write_offset[1:0])),
205-
.read_addr(vgc_address_i),
206-
.read_enable(1'b1),
207-
.read_data(vgc_data_o)
208-
);
209-
210292
endmodule

0 commit comments

Comments
 (0)