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