1 /*************************************************************************
3 * $Id: n8vem.c 1902 2008-05-11 02:40:41Z hharte $ *
5 * Copyright (c) 2007-2008 Howard M. Harte. *
6 * http://www.hartetec.com *
8 * Permission is hereby granted, free of charge, to any person obtaining *
9 * a copy of this software and associated documentation files (the *
10 * "Software"), to deal in the Software without restriction, including *
11 * without limitation the rights to use, copy, modify, merge, publish, *
12 * distribute, sublicense, and/or sell copies of the Software, and to *
13 * permit persons to whom the Software is furnished to do so, subject to *
14 * the following conditions: *
16 * The above copyright notice and this permission notice shall be *
17 * included in all copies or substantial portions of the Software. *
19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, *
20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND *
22 * NONINFRINGEMENT. IN NO EVENT SHALL HOWARD M. HARTE BE LIABLE FOR ANY *
23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, *
24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE *
25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
27 * Except as contained in this notice, the name of Howard M. Harte shall *
28 * not be used in advertising or otherwise to promote the sale, use or *
29 * other dealings in this Software without prior written authorization *
32 * SIMH Interface based on altairz80_hdsk.c, by Peter Schorn. *
34 * Module Description: *
35 * N8VEM Single-Board Computer I/O module for SIMH. *
36 * http://groups.google.com/group/n8vem/web/n8vem-single-board-computer-home-page *
41 *************************************************************************/
45 #include "altairz80_defs.h"
52 #define DBG_PRINT(args) printf args
54 #define DBG_PRINT(args)
62 #define TRACE_MSG 0x80
64 #define N8VEM_MAX_DRIVES 2
66 #define UNIT_V_N8VEM_VERBOSE (UNIT_V_UF + 1) /* verbose mode, i.e. show error messages */
67 #define UNIT_N8VEM_VERBOSE (1 << UNIT_V_N8VEM_VERBOSE)
70 PNP_INFO pnp
; /* Plug and Play */
80 static N8VEM_INFO n8vem_info_data
= { { 0x0, 0x8000, 0x60, 32 } };
81 static N8VEM_INFO
*n8vem_info
= &n8vem_info_data
;
83 extern t_stat
set_membase(UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
84 extern t_stat
show_membase(FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
85 extern t_stat
set_iobase(UNIT
*uptr
, int32 val
, char *cptr
, void *desc
);
86 extern t_stat
show_iobase(FILE *st
, UNIT
*uptr
, int32 val
, void *desc
);
87 extern uint32
sim_map_resource(uint32 baseaddr
, uint32 size
, uint32 resource_type
,
88 int32 (*routine
)(const int32
, const int32
, const int32
), uint8 unmap
);
91 extern int32
find_unit_index (UNIT
*uptr
);
93 static t_stat
n8vem_reset(DEVICE
*n8vem_dev
);
94 static t_stat
n8vem_boot(int32 unitno
, DEVICE
*dptr
);
95 static t_stat
n8vem_attach(UNIT
*uptr
, char *cptr
);
96 static t_stat
n8vem_detach(UNIT
*uptr
);
98 static uint8
N8VEM_Read(const uint32 Addr
);
99 static uint8
N8VEM_Write(const uint32 Addr
, uint8 cData
);
101 static int32
n8vemdev(const int32 port
, const int32 io
, const int32 data
);
102 static int32
n8vem_mem(const int32 port
, const int32 io
, const int32 data
);
104 static int32 trace_level
= 0x00; /* Disable all tracing by default */
105 static int32 save_rom
= 0x00; /* When set to 1, saves ROM back to file on disk at detach time */
106 static int32 save_ram
= 0x00; /* When set to 1, saves RAM back to file on disk at detach time */
107 static int32 n8vem_pio1a
= 0x00; /* 8255 PIO1A IN Port */
108 static int32 n8vem_pio1b
= 0x00; /* 8255 PIO1B OUT Port */
109 static int32 n8vem_pio1c
= 0x00; /* 8255 PIO1C IN Port */
110 static int32 n8vem_pio1ctrl
= 0x00; /* 8255 PIO1 Control Port */
112 #define N8VEM_ROM_SIZE (1024 * 1024)
113 #define N8VEM_RAM_SIZE (512 * 1024)
115 #define N8VEM_RAM_SELECT (1 << 7)
116 #define N8VEM_RAM_MASK 0x0F
117 #define N8VEM_ROM_MASK 0x1F
118 #define N8VEM_ADDR_MASK 0x7FFF
120 static UNIT n8vem_unit
[] = {
121 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, N8VEM_ROM_SIZE
) },
122 { UDATA (NULL
, UNIT_FIX
+ UNIT_ATTABLE
+ UNIT_DISABLE
+ UNIT_ROABLE
, N8VEM_RAM_SIZE
) }
125 static REG n8vem_reg
[] = {
126 { HRDATA (TRACELEVEL
, trace_level
, 16), },
127 { HRDATA (SAVEROM
, save_rom
, 1), },
128 { HRDATA (SAVERAM
, save_ram
, 1), },
129 { HRDATA (PIO1A
, n8vem_pio1a
, 8), },
130 { HRDATA (PIO1B
, n8vem_pio1b
, 8), },
131 { HRDATA (PIO1C
, n8vem_pio1c
, 8), },
132 { HRDATA (PIO1CTRL
, n8vem_pio1ctrl
, 8), },
136 static MTAB n8vem_mod
[] = {
137 { MTAB_XTD
|MTAB_VDV
, 0, "MEMBASE", "MEMBASE", &set_membase
, &show_membase
, NULL
},
138 { MTAB_XTD
|MTAB_VDV
, 0, "IOBASE", "IOBASE", &set_iobase
, &show_iobase
, NULL
},
139 /* quiet, no warning messages */
140 { UNIT_N8VEM_VERBOSE
, 0, "QUIET", "QUIET", NULL
},
141 /* verbose, show warning messages */
142 { UNIT_N8VEM_VERBOSE
, UNIT_N8VEM_VERBOSE
, "VERBOSE", "VERBOSE", NULL
},
147 "N8VEM", n8vem_unit
, n8vem_reg
, n8vem_mod
,
148 N8VEM_MAX_DRIVES
, 10, 31, 1, N8VEM_MAX_DRIVES
, N8VEM_MAX_DRIVES
,
149 NULL
, NULL
, &n8vem_reset
,
150 &n8vem_boot
, &n8vem_attach
, &n8vem_detach
,
151 &n8vem_info_data
, (DEV_DISABLE
| DEV_DIS
), 0,
156 static t_stat
n8vem_reset(DEVICE
*dptr
)
158 PNP_INFO
*pnp
= (PNP_INFO
*)dptr
->ctxt
;
160 TRACE_PRINT(TRACE_MSG
, ("N8VEM: Reset." NLP
));
162 if(dptr
->flags
& DEV_DIS
) { /* Disconnect I/O Ports */
163 sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &n8vemdev
, TRUE
);
164 sim_map_resource(pnp
->mem_base
, pnp
->mem_size
, RESOURCE_TYPE_MEMORY
, &n8vem_mem
, TRUE
);
165 free(n8vem_info
->ram
);
166 free(n8vem_info
->rom
);
168 /* Connect N8VEM at base address */
169 if(sim_map_resource(pnp
->io_base
, pnp
->io_size
, RESOURCE_TYPE_IO
, &n8vemdev
, FALSE
) != 0) {
170 printf("%s: error mapping I/O resource at 0x%04x\n", __FUNCTION__
, pnp
->io_base
);
173 /* Connect N8VEM Memory (512K RAM, 1MB FLASH) */
174 if(sim_map_resource(pnp
->mem_base
, pnp
->mem_size
, RESOURCE_TYPE_MEMORY
, &n8vem_mem
, FALSE
) != 0) {
175 printf("%s: error mapping MEM resource at 0x%04x\n", __FUNCTION__
, pnp
->mem_base
);
179 n8vem_info
->ram
= calloc(1, (N8VEM_RAM_SIZE
));
180 n8vem_info
->rom
= calloc(1, (N8VEM_ROM_SIZE
));
182 /* Clear the RAM and ROM mapping registers */
183 n8vem_info
->mpcl_ram
= 0;
184 n8vem_info
->mpcl_rom
= 0;
189 static t_stat
n8vem_boot(int32 unitno
, DEVICE
*dptr
)
191 TRACE_PRINT(TRACE_MSG
, ("N8VEM: Boot." NLP
));
193 /* Clear the RAM and ROM mapping registers */
194 n8vem_info
->mpcl_ram
= 0;
195 n8vem_info
->mpcl_rom
= 0;
197 /* Set the PC to 0, and go. */
198 *((int32
*) sim_PC
->loc
) = 0;
203 static t_stat
n8vem_attach(UNIT
*uptr
, char *cptr
)
208 i
= find_unit_index(uptr
);
214 r
= attach_unit(uptr
, cptr
); /* attach unit */
215 if ( r
!= SCPE_OK
) /* error? */
218 /* Determine length of this disk */
219 uptr
->capac
= sim_fsize(uptr
->fileref
);
221 TRACE_PRINT(TRACE_MSG
, ("N8VEM: Attach %s." NLP
, i
== 0 ? "ROM" : "RAM"));
223 if(i
== 0) { /* Attaching ROM */
224 n8vem_info
->rom_attached
= TRUE
;
227 memset(n8vem_info
->rom
, 0xFF, N8VEM_ROM_SIZE
);
229 if(uptr
->capac
> 0) {
230 /* Only read in enough of the file to fill the ROM. */
231 if(uptr
->capac
> N8VEM_ROM_SIZE
) uptr
->capac
= N8VEM_ROM_SIZE
;
233 printf("Reading %d bytes into ROM.\n", uptr
->capac
);
234 fread((void *)(n8vem_info
->rom
), uptr
->capac
, 1, uptr
->fileref
);
236 } else { /* attaching RAM */
238 memset(n8vem_info
->ram
, 0x00, N8VEM_RAM_SIZE
);
240 if(uptr
->capac
> 0) {
241 /* Only read in enough of the file to fill the RAM. */
242 if(uptr
->capac
> N8VEM_RAM_SIZE
) uptr
->capac
= N8VEM_RAM_SIZE
;
244 printf("Reading %d bytes into RAM.\n", uptr
->capac
);
245 fread((void *)(n8vem_info
->ram
), uptr
->capac
, 1, uptr
->fileref
);
252 static t_stat
n8vem_detach(UNIT
*uptr
)
257 i
= find_unit_index(uptr
);
263 TRACE_PRINT(TRACE_MSG
, ("N8VEM: Detach %s." NLP
, i
== 0 ? "ROM" : "RAM"));
265 /* rewind to the beginning of the file. */
266 fseek(uptr
->fileref
, 0, SEEK_SET
);
268 if(i
== 0) { /* ROM */
269 /* Save the ROM back to disk if SAVEROM is set. */
271 printf("Writing %d bytes into ROM image.\n", N8VEM_ROM_SIZE
);
272 fwrite((void *)(n8vem_info
->rom
), N8VEM_ROM_SIZE
, 1, uptr
->fileref
);
275 /* Save the RAM back to disk if SAVERAM is set. */
277 printf("Writing %d bytes into RAM image.\n", N8VEM_RAM_SIZE
);
278 fwrite((void *)(n8vem_info
->ram
), N8VEM_RAM_SIZE
, 1, uptr
->fileref
);
281 r
= detach_unit(uptr
); /* detach unit */
286 /* RAM MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3 ) INFORMATION
288 * 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE $0000-$7FFF
290 * : : : : : : : :--0 = A15 RAM ADDRESS LINE DEFAULT IS 0
291 * : : : : : : :----0 = A16 RAM ADDRESS LINE DEFAULT IS 0
292 * : : : : : :------0 = A17 RAM ADDRESS LINE DEFAULT IS 0
293 * : : : : :--------0 = A18 RAM ADDRESS LINE DEFAULT IS 0
294 * : : : :-----------0 =
295 * : : :-------------0 =
296 * : :---------------0 =
297 * :-----------------0 =
299 * ROM MEMORY PAGE CONFIGURATION LATCH CONTROL PORT ( IO_Y3+$04 ) INFORMATION
301 * 7 6 5 4 3 2 1 0 ONLY APPLICABLE TO THE LOWER MEMORY PAGE $0000-$7FFF
303 * : : : : : : : :--0 = A15 ROM ADDRESS LINE DEFAULT IS 0
304 * : : : : : : :----0 = A16 ROM ADDRESS LINE DEFAULT IS 0
305 * : : : : : :------0 = A17 ROM ADDRESS LINE DEFAULT IS 0
306 * : : : : :--------0 = A18 ROM ADDRESS LINE DEFAULT IS 0
307 * : : : :-----------0 = A19 ROM ONLY ADDRESS LINE DEFAULT IS 0
308 * : : :-------------0 =
309 * : :---------------0 =
310 * :-----------------0 = ROM SELECT (0=ROM, 1=RAM) DEFAULT IS 0
312 static int32
n8vem_mem(const int32 Addr
, const int32 write
, const int32 data
)
314 /* DBG_PRINT(("N8VEM: ROM %s, Addr %04x" NLP, write ? "WR" : "RD", Addr)); */
316 if(n8vem_info
->mpcl_rom
& N8VEM_RAM_SELECT
)
318 n8vem_info
->ram
[((n8vem_info
->mpcl_ram
& N8VEM_RAM_MASK
) << 15) | (Addr
& N8VEM_ADDR_MASK
)] = data
;
321 n8vem_info
->rom
[((n8vem_info
->mpcl_rom
& N8VEM_ROM_MASK
) << 15) | (Addr
& N8VEM_ADDR_MASK
)] = data
;
323 TRACE_PRINT(ROM_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR ROM[0x%05x]: Cannot write to ROM." NLP
, PCX
, ((n8vem_info
->mpcl_rom
& N8VEM_ROM_MASK
) << 15) | (Addr
& N8VEM_ADDR_MASK
)));
328 if(n8vem_info
->mpcl_rom
& N8VEM_RAM_SELECT
)
330 return n8vem_info
->ram
[((n8vem_info
->mpcl_ram
& N8VEM_RAM_MASK
) << 15) | (Addr
& N8VEM_ADDR_MASK
)];
332 return n8vem_info
->rom
[((n8vem_info
->mpcl_rom
& N8VEM_ROM_MASK
) << 15) | (Addr
& N8VEM_ADDR_MASK
)];
337 static int32
n8vemdev(const int32 port
, const int32 io
, const int32 data
)
339 /* DBG_PRINT(("N8VEM: IO %s, Port %02x\n", io ? "WR" : "RD", port)); */
341 N8VEM_Write(port
, data
);
344 return(N8VEM_Read(port
));
348 #define N8VEM_PIO1A 0x00 /* (INPUT) IN 1-8 */
349 #define N8VEM_PIO1B 0x01 /* (OUTPUT) OUT TO LEDS */
350 #define N8VEM_PIO1C 0x02 /* (INPUT) */
351 #define N8VEM_PIO1CONT 0x03 /* CONTROL BYTE PIO 82C55 */
353 #define N8VEM_UART_DATA 0x08
354 #define N8VEM_UART_RSR 0x09
355 #define N8VEM_UART_INTR 0x0A
356 #define N8VEM_UART_LCR 0x0B
357 #define N8VEM_UART_MCR 0x0C
358 #define N8VEM_UART_LSR 0x0D
359 #define N8VEM_UART_MSR 0x0E
360 #define N8VEM_UART_SCR 0x0F
362 #define N8VEM_MPCL_RAM 0x18 /* RAM Address control port */
363 #define N8VEM_MPCL_RAM1 0x19 /* RAM Address control port */
364 #define N8VEM_MPCL_RAM2 0x1A /* RAM Address control port */
365 #define N8VEM_MPCL_RAM3 0x1B /* RAM Address control port */
366 #define N8VEM_MPCL_ROM 0x1C /* ROM Address control port */
367 #define N8VEM_MPCL_ROM1 0x1D /* ROM Address control port */
368 #define N8VEM_MPCL_ROM2 0x1E /* ROM Address control port */
369 #define N8VEM_MPCL_ROM3 0x1F /* ROM Address control port */
371 extern int32
sio0d(const int32 port
, const int32 io
, const int32 data
);
372 extern int32
sio0s(const int32 port
, const int32 io
, const int32 data
);
374 static uint8
N8VEM_Read(const uint32 Addr
)
378 switch(Addr
& 0x1F) {
380 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: PIO1A" NLP
, PCX
));
384 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: PIO1B" NLP
, PCX
));
388 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: PIO1C" NLP
, PCX
));
392 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: PIO1CTRL" NLP
, PCX
));
393 cData
= n8vem_pio1ctrl
;
396 cData
= n8vem_info
->uart_lcr
;
398 case N8VEM_UART_DATA
:
401 case N8VEM_UART_INTR
:
404 TRACE_PRINT(UART_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD[%02x]: UART not Implemented." NLP
, PCX
, Addr
));
406 case N8VEM_UART_SCR
: /* 16550 Scratchpad, implemented so software can detect UART is present */
407 cData
= n8vem_info
->uart_scr
;
410 case N8VEM_MPCL_RAM1
:
411 case N8VEM_MPCL_RAM2
:
412 case N8VEM_MPCL_RAM3
:
413 TRACE_PRINT(MPCL_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: MPCL_RAM not Implemented." NLP
, PCX
));
416 case N8VEM_MPCL_ROM1
:
417 case N8VEM_MPCL_ROM2
:
418 case N8VEM_MPCL_ROM3
:
419 TRACE_PRINT(MPCL_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD: MPCL_ROM not Implemented." NLP
, PCX
));
422 TRACE_PRINT(TRACE_MSG
, ("N8VEM: " ADDRESS_FORMAT
" RD[%02x]: not Implemented." NLP
, PCX
, Addr
));
430 static uint8
N8VEM_Write(const uint32 Addr
, uint8 cData
)
433 switch(Addr
& 0x1F) {
435 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: PIO1A=0x%02x" NLP
, PCX
, cData
));
439 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: PIO1B=0x%02x" NLP
, PCX
, cData
));
443 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: PIO1C=0x%02x" NLP
, PCX
, cData
));
447 TRACE_PRINT(PIO_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: PIO1_CTRL=0x%02x" NLP
, PCX
, cData
));
448 n8vem_pio1ctrl
= cData
;
451 TRACE_PRINT(UART_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: UART LCR=%02x." NLP
, PCX
, cData
));
452 n8vem_info
->uart_lcr
= cData
;
454 case N8VEM_UART_DATA
:
456 case N8VEM_UART_INTR
:
460 TRACE_PRINT(UART_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR[%02x]: UART not Implemented." NLP
, PCX
, Addr
));
462 case N8VEM_UART_SCR
: /* 16550 Scratchpad, implemented so software can detect UART is present */
463 n8vem_info
->uart_scr
= cData
;
466 case N8VEM_MPCL_RAM1
:
467 case N8VEM_MPCL_RAM2
:
468 case N8VEM_MPCL_RAM3
:
469 TRACE_PRINT(MPCL_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: MPCL_RAM=0x%02x" NLP
, PCX
, cData
));
470 n8vem_info
->mpcl_ram
= cData
;
473 case N8VEM_MPCL_ROM1
:
474 case N8VEM_MPCL_ROM2
:
475 case N8VEM_MPCL_ROM3
:
476 TRACE_PRINT(MPCL_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR: MPCL_ROM=0x%02x" NLP
, PCX
, cData
));
477 n8vem_info
->mpcl_rom
= cData
;
480 TRACE_PRINT(TRACE_MSG
, ("N8VEM: " ADDRESS_FORMAT
" WR[0x%02x]=0x%02x: not Implemented." NLP
, PCX
, Addr
, cData
));