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