Xemu [doxygen]  hyppo 0a42be3a057156924bc1b626a687bd6e27349c45 @ Sat 19 Mar 02:15:11 CET 2022
primoemu.c
Go to the documentation of this file.
1 /* Xep128: Minimalistic Enterprise-128 emulator with focus on "exotic" hardware
2  Copyright (C)2016 LGB (Gábor Lénárt) <lgblgblgb@gmail.com>
3  http://xep128.lgb.hu/
4 
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
9 
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18 
19 #include "xep128.h"
20 #include "primoemu.h"
21 #include "xemu/z80.h"
22 #include "cpu.h"
23 #include "dave.h"
24 #include "nick.h"
25 #include "zxemu.h"
26 
27 #include "main.h"
28 
29 
30 
31 int primo_on = 0;
33 int primo_rom_seg = -1;
34 
35 
36 // translates EP keyboard matrix positions into Primo scan keys, indexed by primo scan keys
38  0x22, // scan 0 Y
39  0x73, // scan 1 UP-ARROW
40  0x15, // scan 2 S
41  0x07, // scan 3 SHIFT
42  0x25, // scan 4 E
43  0xFF, // scan 5 UPPER
44  0x26, // scan 6 W
45  0x17, // scan 7 CTR
46  0x13, // scan 8 D
47  0x35, // scan 9 3 #
48  0x05, // scan 10 X
49  0x36, // scan 11 2 "
50  0x21, // scan 12 Q
51  0x31, // scan 13 1 !
52  0x16, // scan 14 A
53  0x71, // scan 15 DOWN-ARROW
54  0x03, // scan 16 C
55  0xFF, // scan 17 ----
56  0x14, // scan 18 F
57  0xFF, // scan 19 ----
58  0x23, // scan 20 R
59  0xFF, // scan 21 ----
60  0x24, // scan 22 T
61  0x30, // scan 23 7 /
62  0x10, // scan 24 H
63  0x86, // scan 25 SPACE
64  0x02, // scan 26 B
65  0x32, // scan 27 6 &
66  0x12, // scan 28 G
67  0x34, // scan 29 5 %
68  0x04, // scan 30 V
69  0x33, // scan 31 4 $
70  0x00, // scan 32 N
71  0x50, // scan 33 8 (
72  0x06, // scan 34 Z
73  0xFF, // scan 35 + ?
74  0x20, // scan 36 U
75  0x54, // scan 37 0
76  0x60, // scan 38 J
77  0xFF, // scan 39 > <
78  0x64, // scan 40 L
79  0x53, // scan 41 - i
80  0x62, // scan 42 K
81  0x84, // scan 43 . :
82  0x80, // scan 44 M
83  0x52, // scan 45 9 ;
84  0x90, // scan 46 I
85  0x82, // scan 47 ,
86  0xFF, // scan 48 U"
87  0x65, // scan 49 ' #
88  0x94, // scan 50 P
89  0xFF, // scan 51 u' u"
90  0x92, // scan 52 O
91  0xFF, // scan 53 CLS
92  0xFF, // scan 54 ----
93  0x76, // scan 55 RETURN
94  0xFF, // scan 56 ----
95  0x75, // scan 57 LEFT-ARROW
96  0xFF, // scan 58 E'
97  0xFF, // scan 59 o'
98  0xFF, // scan 60 A'
99  0x72, // scan 61 RIGHT-ARROW
100  0xFF, // scan 62 O:
101  0x37 // scan 63 BRK
102 };
103 
104 
105 #define EP_KBDM_SCAN(sc,resval) ((kbd_matrix[(sc) >> 4] & (1 << ((sc) & 15))) ? 0 : (resval))
106 
107 // F1
108 #define PRIMOEMU_HOTKEY_RESET 0x47
109 
110 
112 {
113  if (data & 128) {
114  if (data & 64)
115  primo_write_io(0, 0);
116  if (primo_on)
117  return;
118  primo_on = 0x40; // the value is important, used by port "limit" for lower primo area!
119  zxemu_switch(0); // switch ZX Spectrum emulation off, if already enabled for some reason ...
120  } else {
121  if (!primo_on)
122  return;
123  primo_on = 0;
124  }
125  DEBUG("PRIMOEMU: emulation is turned %s." NL, primo_on ? "ON" : "OFF");
126  nmi_pending = 0;
127 }
128 
129 
130 static int primo_scan_key ( int scan )
131 {
132  scan = primo_key_trans[scan];
133  if (scan == 0xFF) return 0;
134  return EP_KBDM_SCAN(scan, 1);
135 }
136 
137 
139 {
140  // Primo does the very same for all I/O ports in the range of 0-3F!
141  // EXCEPT bit 0 which is the state of the key given by the port number.
142  return (vsync ? 32 : 0) | EP_KBDM_SCAN(PRIMOEMU_HOTKEY_RESET, 2) | primo_scan_key(port);
143 }
144 
145 
146 #define LD1HI_PV1 (((PRIMO_VID_SEG << 6) + 0x28) & 0xFF)
147 #define LD1HI_PV0 (((PRIMO_VID_SEG << 6) + 0x08) & 0xFF)
148 
149 
151 {
152  // Primo does the very same for all I/O ports in the range of 0-3F!
153  primo_nmi_enabled = data & 128; // bit 7: NMI enabled, this variable is "cloned" as nmi_pending by VINT in dave.c
154  ports[0xA8] = ports[0xAC] = (data & 16) ? 63 : 0; // bit 4, speaker control, pass to Dave in D/A mode
155  memory[(PRIMO_LPT_SEG << 14) + 5] = (data & 8) ? LD1HI_PV1 : LD1HI_PV0; // bit 3: display page: set LPB LD1 high (LPB should be at segment 0xFD, and 0xFC is for primo 0xC000-0xFFFF)
156 }
157 
158 
159 int primo_search_rom ( void )
160 {
161  int a;
162  for (a = 0; a < 0xFC; a++)
163  if (memory_segment_map[a] == ROM_SEGMENT && !memcmp(memory + (a << 14) + 0x168, "PRIMO", 5)) {
164  DEBUG("PRIMO: found Primo ROM in segment %02Xh, good" NL, a);
165  return a;
166  }
167  DEBUG("PRIMO: not found Primo ROM in the loaded ROMs ..." NL);
168  return -1;
169 }
170 
171 
172 static const Uint8 primo_lpt[] = {
173  // the USEFULL area of the screen, this must be the FIRST LPB in our LPT.
174  // LPIXEL 2 colour mode is used, 192 scanlines are used
175  256-192,14|16, 15, 47, 0,0,0,0, 1,0xFF,0,0,0,0,0,0,
176  // bottom not used area ... 47 scanlines
177  256-47, 2 | 128, 6, 63, 0,0,0,0, 0,0,0,0,0,0,0,0, // 128 = ask for VINT, which is cloned as NMI in primo mode
178  // SYNC etc stuffs ...
179  256-3 , 0, 63, 0, 0,0,0,0, 0,0,0,0,0,0,0,0,
180  256-2 , 0, 6, 63, 0,0,0,0, 0,0,0,0,0,0,0,0,
181  256-1 , 0, 63, 32, 0,0,0,0, 0,0,0,0,0,0,0,0,
182  256-19, 2, 6, 63, 0,0,0,0, 0,0,0,0,0,0,0,0,
183  // upper not used area ... 48 scanlines, the RELOAD bit must be set!!!!
184  256-48, 3, 6, 63, 0,0,0,0, 0,0,0,0,0,0,0,0
185 };
186 #define MEMORY_BACKUP_SIZE (0xC000 + sizeof primo_lpt)
187 static Uint8 memory_backup[MEMORY_BACKUP_SIZE];
188 static Uint8 ports_backup[0x100];
189 static Z80EX_CONTEXT z80ex_backup;
190 
191 
192 
193 void primo_emulator_exit ( void )
194 {
195  int a;
196  ports_backup[0x83] |= 128 | 64;
197  for (a = 0x80; a < 0x84; a++)
198  z80ex_pwrite_cb(a, ports_backup[a]); // restore Nick registers
199  for (a = 0xA0; a < 0xB5; a++)
200  z80ex_pwrite_cb(a, ports_backup[a]); // restore Dave registers
201  memcpy(memory + 0xFA * 0x4000, memory_backup, MEMORY_BACKUP_SIZE); // restore memory
202  primo_switch(0); // turn Primo mode OFF
203  //z80ex.int = 1; // enable interrupts (?)
204  //memcpy(&z80ex, &z80ex_backup, sizeof(Z80EX_CONTEXT));
205  //z80ex.prefix = 0; // turn prefix off, because last opc was the ED trap for XEP ROM!
206  //Z80_PC--; // nah ...
207  //xep_accept_trap = 0;
209 }
210 
211 
213 {
214  int a;
215  /* Save state of various things to be able to revert into EP mode later, without any data lost */
216  memcpy(memory_backup, memory + 0xFA * 0x4000, MEMORY_BACKUP_SIZE); // save memory
217  memcpy(ports_backup, ports, 0x100); // backup ports [note: on restore, we don't want to rewrite all values, maybe only Dave/Nick!
218  memcpy(&z80ex_backup, &z80ex, sizeof(Z80EX_CONTEXT));
219 
220 // memcpy(); // save Dave registers
221 // memcpy(); // save Nick registers
222 
223  /* set an LPT */
224  memcpy(memory + (PRIMO_LPT_SEG << 14), primo_lpt, sizeof primo_lpt);
225  z80ex_pwrite_cb(0x82, (PRIMO_LPT_SEG << 10) & 0xFF); // LPT address, low byte
226  z80ex_pwrite_cb(0x83, ((PRIMO_LPT_SEG << 2) & 0xF));
227  z80ex_pwrite_cb(0x83, ((PRIMO_LPT_SEG << 2) & 0xF) | 64);
228  z80ex_pwrite_cb(0x83, ((PRIMO_LPT_SEG << 2) & 0xF) | 64 | 128);
229  z80ex_pwrite_cb(0x81, 0); // border color
230  /* do our stuffs ... */
231  z80ex_pwrite_cb(0xA7, 8 | 16); // D/A mode for Dave audio
232  for (a = 0xA8; a < 0xB0; a++)
233  z80ex_pwrite_cb(a, 0); // volumes of L/H channels
234  z80ex_pwrite_cb(0xB4, 0xAA); // disable all interrupts on Dave (z80 won't get INT but the cloned NMI directly from Nick "translated" from VINT) and reset latches
235  z80ex_pwrite_cb(0xB0, PRIMO_ROM_SEG); // first segment is the Primo ROM now
236  z80ex_pwrite_cb(0xB1, PRIMO_MEM1_SEG); // normal RAM segment
237  z80ex_pwrite_cb(0xB2, PRIMO_MEM2_SEG); // normal RAM segment
238  z80ex_pwrite_cb(0xB3, PRIMO_VID_SEG); // a video segment as the Primo video RAM
239  primo_switch(128 | 64); // turn on Primo I/O mode
240  Z80_PC = 0; // Z80 reset address to the Primo ROM
241  z80ex_reset(); // reset the CPU only!!
242  set_ep_cpu(CPU_Z80); // good old Z80 NMOS CPU is selected
243  set_cpu_clock(2500000);
244 }
245 
PRIMO_VID_SEG
#define PRIMO_VID_SEG
Definition: primoemu.h:23
z80ex_pwrite_cb
void z80ex_pwrite_cb(Z80EX_WORD port16, Z80EX_BYTE value)
Definition: cpu.c:396
PRIMO_LPT_SEG
#define PRIMO_LPT_SEG
Definition: primoemu.h:22
primo_key_trans
const Uint8 primo_key_trans[]
Definition: primoemu.c:36
zxemu.h
LD1HI_PV0
#define LD1HI_PV0
Definition: primoemu.c:147
set_ep_cpu
void set_ep_cpu(int type)
Definition: cpu.c:74
primo_emulator_exit
void primo_emulator_exit(void)
Definition: primoemu.c:192
PRIMO_ROM_SEG
#define PRIMO_ROM_SEG
Definition: primoemu.h:26
DEFAULT_CPU_CLOCK
#define DEFAULT_CPU_CLOCK
Definition: enterprise128.h:34
dave.h
PRIMO_MEM2_SEG
#define PRIMO_MEM2_SEG
Definition: primoemu.h:24
m65-memcontent-generator.data
data
Definition: m65-memcontent-generator.py:119
z80ex_reset
void z80ex_reset(void)
Definition: z80ex.c:156
LD1HI_PV1
#define LD1HI_PV1
Definition: primoemu.c:146
Uint8
uint8_t Uint8
Definition: fat32.c:51
_z80_cpu_context
Definition: z80ex.h:143
set_cpu_clock
int set_cpu_clock(int hz)
Definition: enterprise128.c:91
cpu.h
PRIMO_MEM1_SEG
#define PRIMO_MEM1_SEG
Definition: primoemu.h:25
z80.h
memory_segment_map
const char * memory_segment_map[0x100]
Definition: cpu.c:44
primo_rom_seg
int primo_rom_seg
Definition: primoemu.c:32
CPU_Z80
#define CPU_Z80
Definition: cpu.h:24
NL
#define NL
Definition: fat32.c:37
memory
Uint8 memory[0x100000]
Definition: commodore_65.c:43
primo_nmi_enabled
int primo_nmi_enabled
Definition: primoemu.c:31
primo_emulator_execute
void primo_emulator_execute(void)
Definition: primoemu.c:211
primo_search_rom
int primo_search_rom(void)
Definition: primoemu.c:158
xep128.h
main.h
Z80_PC
#define Z80_PC
Definition: z80ex.h:121
primo_switch
void primo_switch(Uint8 data)
Definition: primoemu.c:110
zxemu_switch
void zxemu_switch(Uint8 data)
Definition: zxemu.c:32
primo_read_io
Uint8 primo_read_io(Uint8 port)
Definition: primoemu.c:137
PRIMOEMU_HOTKEY_RESET
#define PRIMOEMU_HOTKEY_RESET
Definition: primoemu.c:108
z80ex
Z80EX_CONTEXT z80ex
Definition: primo.c:37
DEBUG
#define DEBUG(...)
Definition: emutools_basicdefs.h:167
MEMORY_BACKUP_SIZE
#define MEMORY_BACKUP_SIZE
Definition: primoemu.c:186
primoemu.h
vsync
int vsync
Definition: nick.c:49
primo_write_io
void primo_write_io(Uint8 port, Uint8 data)
Definition: primoemu.c:149
primo_on
int primo_on
Definition: primoemu.c:30
ROM_SEGMENT
const char ROM_SEGMENT[]
Definition: cpu.c:51
EP_KBDM_SCAN
#define EP_KBDM_SCAN(sc, resval)
Definition: primoemu.c:105
nick.h
nmi_pending
int nmi_pending
Definition: cpu.c:47