1 /* ula.c: ULA routines
2    Copyright (c) 1999-2011 Philip Kendall, Darren Salt
3 
4    $Id: ula.c 4926 2013-05-05 07:58:18Z sbaldovi $
5 
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10 
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License along
17    with this program; if not, write to the Free Software Foundation, Inc.,
18    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19 
20    Author contact information:
21 
22    E-mail: philip-fuse@shadowmagic.org.uk
23 
24 */
25 
26 #include <config.h>
27 
28 #include <libspectrum.h>
29 
30 #include "compat.h"
31 #include "keyboard.h"
32 #include "loader.h"
33 #include "machine.h"
34 #include "module.h"
35 #include "periph.h"
36 #include "settings.h"
37 #include "sound.h"
38 #include "spectrum.h"
39 #include "tape.h"
40 #include "ula.h"
41 
42 static libspectrum_byte last_byte;
43 
44 libspectrum_byte ula_contention[ ULA_CONTENTION_SIZE ];
45 libspectrum_byte ula_contention_no_mreq[ ULA_CONTENTION_SIZE ];
46 
47 /* What to return if no other input pressed; depends on the last byte
48    output to the ULA; see CSS FAQ | Technical Information | Port #FE
49    for full details */
50 libspectrum_byte ula_default_value;
51 
52 static void ula_from_snapshot( libspectrum_snap *snap );
53 static void ula_to_snapshot( libspectrum_snap *snap );
54 static libspectrum_byte ula_read( libspectrum_word port, int *attached );
55 static void ula_write( libspectrum_word port, libspectrum_byte b );
56 
57 static module_info_t ula_module_info = {
58 
59   NULL,
60   NULL,
61   NULL,
62   ula_from_snapshot,
63   ula_to_snapshot,
64 
65 };
66 
67 static const periph_port_t ula_ports[] = {
68   { 0x0001, 0x0000, ula_read, ula_write },
69   { 0, 0, NULL, NULL }
70 };
71 
72 static const periph_t ula_periph = {
73   NULL,
74   ula_ports,
75   0,
76   NULL
77 };
78 
79 static const periph_port_t ula_ports_full_decode[] = {
80   { 0x00ff, 0x00fe, ula_read, ula_write },
81   { 0, 0, NULL, NULL }
82 };
83 
84 static const periph_t ula_periph_full_decode = {
85   NULL,
86   ula_ports_full_decode,
87   0,
88   NULL
89 };
90 
91 void
ula_init(void)92 ula_init( void )
93 {
94   module_register( &ula_module_info );
95 
96   periph_register( PERIPH_TYPE_ULA, &ula_periph );
97   periph_register( PERIPH_TYPE_ULA_FULL_DECODE, &ula_periph_full_decode );
98 
99   ula_default_value = 0xff;
100 }
101 
102 static libspectrum_byte
ula_read(libspectrum_word port,int * attached)103 ula_read( libspectrum_word port, int *attached )
104 {
105   libspectrum_byte r = ula_default_value;
106 
107   *attached = 1;
108 
109   loader_detect_loader();
110 
111   r &= keyboard_read( port >> 8 );
112   if( tape_microphone ) r ^= 0x40;
113 
114   return r;
115 }
116 
117 /* What happens when we write to the ULA? */
118 static void
ula_write(libspectrum_word port GCC_UNUSED,libspectrum_byte b)119 ula_write( libspectrum_word port GCC_UNUSED, libspectrum_byte b )
120 {
121   last_byte = b;
122 
123   display_set_lores_border( b & 0x07 );
124   sound_beeper( (!!(b & 0x10) << 1) + ( (!(b & 0x8)) | tape_microphone ) );
125 
126   /* FIXME: shouldn't really be using the memory capabilities here */
127 
128   if( machine_current->timex ) {
129 
130     ula_default_value = 0x5f;
131 
132   } else if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_PLUS3_MEMORY ) {
133 
134     ula_default_value = 0xbf;
135 
136   } else if( machine_current->capabilities & LIBSPECTRUM_MACHINE_CAPABILITY_128_MEMORY || !settings_current.issue2 ) {
137 
138     /* 128K always acts like an Issue 3 */
139     ula_default_value = b & 0x10 ? 0xff : 0xbf;
140 
141   } else {
142 
143     /* Issue 2 */
144     ula_default_value = b & 0x18 ? 0xff : 0xbf;
145 
146   }
147 
148 }
149 
150 libspectrum_byte
ula_last_byte(void)151 ula_last_byte( void )
152 {
153   return last_byte;
154 }
155 
156 libspectrum_byte
ula_tape_level(void)157 ula_tape_level( void )
158 {
159   return last_byte & 0x8;
160 }
161 
162 static void
ula_from_snapshot(libspectrum_snap * snap)163 ula_from_snapshot( libspectrum_snap *snap )
164 {
165   ula_write( 0x00fe, libspectrum_snap_out_ula( snap ) );
166   tstates = libspectrum_snap_tstates( snap );
167   settings_current.issue2 = libspectrum_snap_issue2( snap );
168 }
169 
170 static void
ula_to_snapshot(libspectrum_snap * snap)171 ula_to_snapshot( libspectrum_snap *snap )
172 {
173   libspectrum_snap_set_out_ula( snap, last_byte );
174   libspectrum_snap_set_tstates( snap, tstates );
175   libspectrum_snap_set_issue2( snap, settings_current.issue2 );
176 }
177 
178 void
ula_contend_port_early(libspectrum_word port)179 ula_contend_port_early( libspectrum_word port )
180 {
181   if( memory_map_read[ port >> MEMORY_PAGE_SIZE_LOGARITHM ].contended )
182     tstates += ula_contention_no_mreq[ tstates ];
183 
184   tstates++;
185 }
186 
187 void
ula_contend_port_late(libspectrum_word port)188 ula_contend_port_late( libspectrum_word port )
189 {
190   if( machine_current->ram.port_from_ula( port ) ) {
191 
192     tstates += ula_contention_no_mreq[ tstates ]; tstates += 2;
193 
194   } else {
195 
196     if( memory_map_read[ port >> MEMORY_PAGE_SIZE_LOGARITHM ].contended ) {
197       tstates += ula_contention_no_mreq[ tstates ]; tstates++;
198       tstates += ula_contention_no_mreq[ tstates ]; tstates++;
199       tstates += ula_contention_no_mreq[ tstates ];
200     } else {
201       tstates += 2;
202     }
203 
204   }
205 }
206