]> git.ozlabs.org Git - minimigmac.git/blob - fpga/mem_intf.v
Initial commit
[minimigmac.git] / fpga / mem_intf.v
1 /*
2  * Memory interface for Minimigmac
3  *
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
7  *
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.
14  *
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
18  * configurations:
19  *
20  *  System                   Main Screen    Alternate
21  *
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
26  *
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 :-)
31  *
32  * The total size of the video buffer is 0x5580 bytes
33  * 
34  * For audio, we have:
35  *
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
41  * 
42  * Implementation note:
43  * 
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.
47  * 
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.
55  */
56
57 module mem_intf(input                   sysclk,
58                 input                   reset,
59
60                 /* SRAM pins */
61                 inout [15:0]            ram_data,
62                 output [19:1]           ram_address,
63                 output [3:0]            _ram_ce,
64                 output                  _ram_bhe,
65                 output                  _ram_ble,
66                 output                  _ram_we,
67                 output                  _ram_oe,
68
69                 /* Bus interface */
70                 input                   bus_cs_ram,
71                 input                   bus_cs_rom,
72                 input                   bus_we,
73                 output                  bus_ack,
74                 input                   bus_ube,
75                 input                   bus_lbe,
76                 input                   bus_phase,
77                 input [15:0]            bus_wdata,
78                 output [15:0]           bus_rdata,
79                 input [22:1]            bus_addr,
80
81                 /* Backbus interface */
82                 input [5:0]             bb_addr,
83                 input [7:0]             bb_wdata,
84                 output [7:0]            bb_rdata,
85                 input                   bb_strobe,
86                 input                   bb_wr,
87
88                 /* Asynchronous video interface */
89                 input                   vid_bufsel,
90                 input                   vid_req,
91                 output reg              vid_ack,
92                 output reg [15:0]       vid_pixels
93
94                 /* TODO: Audio */
95                 );
96         
97         /* Owner of interface */
98         wire            own_bus;
99         wire            own_vid;
100         wire            own_spi;
101
102         /* Cooked bus address (ram/rom selection) */
103         wire [21:1]     cooked_address;
104         /* Latch of cs_rom vs. cs_ram */
105         reg             rom_select;
106
107         /* SPI byte write latch */
108         reg [21:0]      spi_addr;
109         reg [7:0]       spi_data;
110         reg             spi_pending;    
111         reg             spi_we;
112
113         /* SPI decode signals */
114         wire            spi_wreg;       
115         wire            spi_reg_addr0;
116         wire            spi_reg_addr1;
117         wire            spi_reg_addr2;
118         wire            spi_reg_data;
119
120         /* Muxed/cooked RAM control signals */
121         wire [15:0]     ram_data_out;
122         wire [21:1]     ram_addr;
123
124         /* Main memory enable */
125         wire            ram_en; 
126
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
131          */
132         parameter vid_buf_base = 'h1F2700 / 2;
133         parameter vid_buf_size = 'h2ac0;
134         reg [21:1]      vid_addr;
135         reg [13:0]      vid_words;
136         wire            vid_latch_pix;  
137
138         /* vid_req/vid_ack logic */
139         reg [2:0]       vid_req_sync;
140         reg             vid_req_pending;
141         wire            vid_ack_reset;
142
143         /* State machine */
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;
151
152         /* State bits breakout:
153          *
154          *  7:
155          *  6: own bit video
156          *  5: own bit spi
157          *  4: own bit bus
158          *  3:
159          *  2: inc address (vid/audio)
160          *  1: bus phase
161          *  0: ram active
162          */
163         reg [7:0]       state;
164         
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];
169
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.
173          * 
174          * XX. Remove the "default" case, make it SPI
175          */
176         assign ram_data_out     = own_bus ? bus_wdata :
177                                   own_spi ? { spi_data, spi_data } :
178                                   16'b1;        
179         
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] :
185                                   own_vid ? 1'b0 :
186                                   1'b1;
187         assign _ram_ble         = own_bus ? ~bus_lbe :
188                                   own_spi ? ~spi_addr[0] :
189                                   own_vid ? 1'b0 :
190                                   1'b1;
191
192         /* Cook RAM address based on RAM/ROM selection
193          * We have 2M of RAM and 128k of ROM repeated
194          */
195         assign cooked_address = rom_select ?
196                         { 5'b10000, bus_addr[16:1] } :
197                         { 1'b0, bus_addr[20:1] };
198         
199
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;
204
205         /* Do ram_data input based on _ram_we */
206         assign ram_data = _ram_we ? 16'bz : ram_data_out;
207
208         /* And set ram output enable accordingly */
209         assign _ram_oe = ~_ram_we | ~ram_en;
210
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];
217
218         /* RAM to bus data */
219         assign bus_rdata = own_bus ? ram_data : 16'b1;
220
221         /* Ack for bus request in phase 0. WARNING: Must reproduce
222          * the state machine logic in state_idle
223          */
224         assign bus_ack = state == state_bus0;
225
226         /* Latch rom_select on cs transitions */
227         always@(posedge sysclk or posedge reset) begin
228                 if (reset)
229                   rom_select <= 0;
230                 else begin
231                         if (bus_cs_ram)
232                           rom_select <= 0;
233                         else if (bus_cs_rom)
234                           rom_select <= 1;
235                 end
236         end
237
238         /* State machine */
239         always@(posedge sysclk or posedge reset) begin
240                 if (reset)
241                   state <= state_idle;
242                 else
243                   case(state)
244                           state_idle: begin
245                                   /* Video request */
246                                   if (vid_req_pending)
247                                     state <= state_vid0;
248                                   /* SPI request */
249                                   else if (spi_pending)
250                                     state <= state_spi0;
251                                   /* CPU request */
252                                   else if (bus_cs_ram || bus_cs_rom)
253                                     state <= state_bus0;
254                           end
255                           state_bus0: begin
256                                   /* There should be no possible abort here
257                                    * since we have ack out
258                                    */
259                                   state <= state_bus1;
260                           end                     
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;
266                   endcase
267         end     
268
269         /* vid_req input synchronizer and edge detect */
270         always@(posedge sysclk or posedge reset) begin
271                 if (reset) begin
272                         vid_req_sync <= 3'b000;
273                         vid_req_pending <= 0;                   
274                 end else begin
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;
280                         else if (own_vid)
281                           vid_req_pending <= 0;                 
282                 end
283         end
284        
285         assign vid_ack_reset = reset | ~vid_req_sync[1];
286         assign vid_latch_pix = state == state_vid0;
287  
288         /* vid_ack generation, synchronous set, asynchronous reset */
289         always@(posedge sysclk or posedge vid_ack_reset) begin
290                 if (vid_ack_reset)
291                   vid_ack <= 1'b0;
292                 else if (vid_latch_pix)
293                   vid_ack <= 1'b1;
294         end
295
296         /* vid address calculation */
297         always@(posedge sysclk or posedge reset) begin
298                 if (reset) begin
299                         vid_addr <= vid_buf_base;
300                         vid_addr[15] <= vid_bufsel;                     
301                         vid_words <= vid_buf_size-1;
302                 end else begin
303                         if (state[2]) begin
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;
308                                 end else begin
309                                         vid_addr <= vid_addr + 1;
310                                         vid_words <= vid_words - 1;
311                                 end                             
312                         end
313                 end
314         end
315
316         /* latch pixels */
317         always@(posedge sysclk or posedge reset) begin
318                 if (reset) begin
319                         vid_pixels <= 0;
320                 end else begin
321                         if (vid_latch_pix) begin
322                                 vid_pixels <= ram_data;
323                         end
324                 end
325         end     
326         
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;
337
338         /* SPI control */
339         always@(posedge sysclk or posedge reset) begin
340                 if (reset) begin
341                         spi_pending <= 0;
342                         spi_we <= 0;                    
343                 end else begin
344                         if (bb_strobe && spi_reg_data) begin
345                                 spi_pending <= 1;
346                                 spi_we <= bb_wr;
347                         end else if (own_spi) begin
348                                 spi_pending <= 0;
349                         end
350                 end
351         end
352
353         /* SPI data latch */
354         always@(posedge sysclk or posedge reset) begin
355                 if (reset) begin
356                         spi_data <= 0;
357                 end else 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] :
362                                             ram_data[15:8];
363                         end
364                 end             
365         end     
366         
367         /* SPI address latch write */
368         always@(posedge sysclk or posedge reset) begin
369                 if (reset) begin
370                         spi_addr <= 0;
371                 end else begin
372                         if (own_spi && state[1]) begin
373                                 spi_addr <= spi_addr + 1;
374                         end else if (spi_wreg) begin
375                                 if (spi_reg_addr0)
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;
381                         end
382                 end
383         end
384
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 :
390                           0;
391 endmodule