2 * Memory interface for Minimigmac
4 * Wraps the SRAM chips on the Minimig board and provides
5 * support for RAM and ROM access from the processor,
6 * backbus access via SPI, and "DMA" sound and video buffers
8 * Notes about video: We use a simple req edge based asynchronous
9 * protocol since we are running the main logic separately from
10 * the video timing generator. On each handshake, the memory
11 * interface will fetch the next 16 pixels. Video addresses are
12 * calculated internally based on the buffer select VIA bit for
13 * a fixed resolution of 512x342.
15 * Starting addresses of the video buffers depend on the model
16 * and amount of RAM. We emulate a 2Mb configuration but for
17 * completeness, here are the address for all supported
20 * System Main Screen Alternate
22 * Macintosh Plus, 1Mb $FA700 $F2700
23 * Macintosh Plus, 2Mb $1FA700 $1F2700
24 * Macintosh Plus, 2.5Mb $27A700 $272700
25 * Macintosh Plus, 4Mb $3FA700 $3F2700
27 * The above addresses look confusing but basically it's really
28 * just hard wired chip select I beleive on the real mac tho for
29 * now we just use a full blown latch to hold the address since
30 * we have silicon to spare :-)
32 * The total size of the video buffer is 0x5580 bytes
36 * System Main Sound Alternate
37 * Macintosh Plus, 1Mb $FFD00 $FA100
38 * Macintosh Plus, 2Mb $1FFD00 $1FA100
39 * Macintosh Plus, 2.5Mb $27FD00 $27A100
40 * Macintosh Plus, 4Mb $3FFD00 $3FA100
42 * Implementation note:
44 * This is sub-optimal. We have a 3 cycle round trip, which could
45 * probably go down to one or two (we have a mandatory idle cycle
46 * between 2-cycle accesses). Works for now and is easy tho.
48 * The memory doesn't seem to require any hold times, on synthetized
49 * cycles (video, SPI, ...) we establish everything at once and leave
50 * the signals "on" for 2 cycles. On CPU initiated cycles, some
51 * signals are established later, see comments in the CPU interface
52 * module, but overall it fits the timings. The idle cycle should give
53 * us the necessary resting time to avoid cases of both the memory and
54 * the FPGA trying to drive the data bus.
57 module mem_intf(input sysclk,
61 inout [15:0] ram_data,
62 output [19:1] ram_address,
77 input [15:0] bus_wdata,
78 output [15:0] bus_rdata,
79 input [22:1] bus_addr,
81 /* Backbus interface */
84 output [7:0] bb_rdata,
88 /* Asynchronous video interface */
92 output reg [15:0] vid_pixels
97 /* Owner of interface */
102 /* Cooked bus address (ram/rom selection) */
103 wire [21:1] cooked_address;
104 /* Latch of cs_rom vs. cs_ram */
107 /* SPI byte write latch */
113 /* SPI decode signals */
120 /* Muxed/cooked RAM control signals */
121 wire [15:0] ram_data_out;
122 wire [21:1] ram_addr;
124 /* Main memory enable */
127 /* Video address generator. Buffer select bit is
128 * inserted in there at bit 15. We cound down tho
129 * eventually I may replace that with a reset input
130 * from the video circuitry
132 parameter vid_buf_base = 'h1F2700 / 2;
133 parameter vid_buf_size = 'h2ac0;
135 reg [13:0] vid_words;
138 /* vid_req/vid_ack logic */
139 reg [2:0] vid_req_sync;
144 localparam state_idle = 8'h10; /* idle, ram off, owner is bus */
145 localparam state_bus0 = 8'h11; /* bus access phase 0 */
146 localparam state_bus1 = 8'h13; /* bus access phase 1 */
147 localparam state_spi0 = 8'h21; /* spi access phase 0 */
148 localparam state_spi1 = 8'h23; /* spi access phase 1 */
149 localparam state_vid0 = 8'h41;
150 localparam state_vid1 = 8'h47;
152 /* State bits breakout:
159 * 2: inc address (vid/audio)
165 /* Own lines off the state machine */
166 assign own_bus = state[4];
167 assign own_spi = state[5];
168 assign own_vid = state[6];
170 /* First setup ram_data_out, _ram_we and ram_addr based
171 * on owner. ram_data_out is then applied to ram_data or
172 * not based on _ram_we.
174 * XX. Remove the "default" case, make it SPI
176 assign ram_data_out = own_bus ? bus_wdata :
177 own_spi ? { spi_data, spi_data } :
180 assign ram_en = state[0];
181 assign _ram_we = (own_bus ? (bus_cs_rom | ~bus_we) :
182 own_spi ? ~spi_we : 1'b1) | ~ram_en;
183 assign _ram_bhe = own_bus ? ~bus_ube :
184 own_spi ? spi_addr[0] :
187 assign _ram_ble = own_bus ? ~bus_lbe :
188 own_spi ? ~spi_addr[0] :
192 /* Cook RAM address based on RAM/ROM selection
193 * We have 2M of RAM and 128k of ROM repeated
195 assign cooked_address = rom_select ?
196 { 5'b10000, bus_addr[16:1] } :
197 { 1'b0, bus_addr[20:1] };
200 /* Mux appropriate source of RAM address */
201 assign ram_addr = own_bus ? cooked_address :
202 own_spi ? spi_addr[21:1] :
203 own_vid ? vid_addr : 0;
205 /* Do ram_data input based on _ram_we */
206 assign ram_data = _ram_we ? 16'bz : ram_data_out;
208 /* And set ram output enable accordingly */
209 assign _ram_oe = ~_ram_we | ~ram_en;
211 /* Split ram_addr into banks */
212 assign ram_address = ram_addr[19:1];
213 assign _ram_ce[0] = ~(ram_addr[21:20] == 2'b00) | ~state[0];
214 assign _ram_ce[1] = ~(ram_addr[21:20] == 2'b01) | ~state[0];
215 assign _ram_ce[2] = ~(ram_addr[21:20] == 2'b10) | ~state[0];
216 assign _ram_ce[3] = ~(ram_addr[21:20] == 2'b11) | ~state[0];
218 /* RAM to bus data */
219 assign bus_rdata = own_bus ? ram_data : 16'b1;
221 /* Ack for bus request in phase 0. WARNING: Must reproduce
222 * the state machine logic in state_idle
224 assign bus_ack = state == state_bus0;
226 /* Latch rom_select on cs transitions */
227 always@(posedge sysclk or posedge reset) begin
239 always@(posedge sysclk or posedge reset) begin
249 else if (spi_pending)
252 else if (bus_cs_ram || bus_cs_rom)
256 /* There should be no possible abort here
257 * since we have ack out
261 state_bus1: state <= state_idle;
262 state_spi0: state <= state_spi1;
263 state_spi1: state <= state_idle;
264 state_vid0: state <= state_vid1;
265 state_vid1: state <= state_idle;
269 /* vid_req input synchronizer and edge detect */
270 always@(posedge sysclk or posedge reset) begin
272 vid_req_sync <= 3'b000;
273 vid_req_pending <= 0;
275 vid_req_sync[2] <= vid_req_sync[1];
276 vid_req_sync[1] <= vid_req_sync[0];
277 vid_req_sync[0] <= vid_req;
278 if (vid_req_sync[2] == 0 && vid_req_sync[1])
279 vid_req_pending <= 1;
281 vid_req_pending <= 0;
285 assign vid_ack_reset = reset | ~vid_req_sync[1];
286 assign vid_latch_pix = state == state_vid0;
288 /* vid_ack generation, synchronous set, asynchronous reset */
289 always@(posedge sysclk or posedge vid_ack_reset) begin
292 else if (vid_latch_pix)
296 /* vid address calculation */
297 always@(posedge sysclk or posedge reset) begin
299 vid_addr <= vid_buf_base;
300 vid_addr[15] <= vid_bufsel;
301 vid_words <= vid_buf_size-1;
304 if (vid_words == 0) begin
305 vid_addr <= vid_buf_base;
306 vid_addr[15] <= vid_bufsel;
307 vid_words <= vid_buf_size-1;
309 vid_addr <= vid_addr + 1;
310 vid_words <= vid_words - 1;
317 always@(posedge sysclk or posedge reset) begin
321 if (vid_latch_pix) begin
322 vid_pixels <= ram_data;
327 /* SPI register interface */
328 `define MEMINTF_REG_ADDR0 0
329 `define MEMINTF_REG_ADDR1 1
330 `define MEMINTF_REG_ADDR2 2
331 `define MEMINTF_REG_DATA 3
332 assign spi_wreg = bb_strobe && bb_wr;
333 assign spi_reg_addr0 = bb_addr[2:0] == `MEMINTF_REG_ADDR0;
334 assign spi_reg_addr1 = bb_addr[2:0] == `MEMINTF_REG_ADDR1;
335 assign spi_reg_addr2 = bb_addr[2:0] == `MEMINTF_REG_ADDR2;
336 assign spi_reg_data = bb_addr[2:0] == `MEMINTF_REG_DATA;
339 always@(posedge sysclk or posedge reset) begin
344 if (bb_strobe && spi_reg_data) begin
347 end else if (own_spi) begin
354 always@(posedge sysclk or posedge reset) begin
358 if (spi_wreg && spi_reg_data) begin
359 spi_data <= bb_wdata;
360 end else if (own_spi && !spi_we && state[1]) begin
361 spi_data <= spi_addr[0] ? ram_data[7:0] :
367 /* SPI address latch write */
368 always@(posedge sysclk or posedge reset) begin
372 if (own_spi && state[1]) begin
373 spi_addr <= spi_addr + 1;
374 end else if (spi_wreg) begin
376 spi_addr[21:16] <= bb_wdata[5:0];
377 else if (spi_reg_addr1)
378 spi_addr[15:8] <= bb_wdata;
379 else if (spi_reg_addr2)
380 spi_addr[7:0] <= bb_wdata;
385 /* SPI backbus register read logic */
386 assign bb_rdata = spi_reg_addr0 ? { 2'b0, spi_addr[21:16] } :
387 spi_reg_addr1 ? spi_addr[15:8] :
388 spi_reg_addr2 ? spi_addr[7:0] :
389 spi_reg_data ? spi_data :