1 /*
2  *  Copyright (C) 2005-2019  Anders Gavare.  All rights reserved.
3  *
4  *  Redistribution and use in source and binary forms, with or without
5  *  modification, are permitted provided that the following conditions are met:
6  *
7  *  1. Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  *  2. Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *  3. The name of the author may not be used to endorse or promote products
13  *     derived from this software without specific prior written permission.
14  *
15  *  THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  *  ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  *  ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  *  FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  *  DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  *  OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  *  HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  *  OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  *  SUCH DAMAGE.
26  *
27  *
28  *  COMMENT: PC CMOS/RTC device (ISA ports 0x70 and 0x71)
29  *
30  *  The main point of this device is to be a "PC style wrapper" for accessing
31  *  the MC146818 (the RTC). In most other respects, this device is bogus, and
32  *  just acts as a 256-byte RAM device.
33  */
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 
39 #include "cpu.h"
40 #include "device.h"
41 #include "devices.h"
42 #include "emul.h"
43 #include "machine.h"
44 #include "memory.h"
45 #include "misc.h"
46 
47 
48 #define	DEV_PCCMOS_LENGTH		2
49 #define	PCCMOS_MC146818_FAKE_ADDR	0x1d00000000ULL
50 
51 struct pccmos_data {
52 	unsigned char	select;
53 	unsigned char	ram[256];
54 };
55 
56 
DEVICE_ACCESS(pccmos)57 DEVICE_ACCESS(pccmos)
58 {
59 	struct pccmos_data *d = (struct pccmos_data *) extra;
60 	uint64_t idata = 0, odata = 0;
61 	unsigned char b = 0;
62 	int r = 1;
63 
64 	if (writeflag == MEM_WRITE)
65 		b = idata = memory_readmax64(cpu, data, len);
66 
67 	/*
68 	 *  Accesses to CMOS register 0 .. 0xd are rerouted to the
69 	 *  RTC; all other access are treated as CMOS RAM read/writes.
70 	 */
71 
72 	if ((relative_addr & 1) == 0) {
73 		if (writeflag == MEM_WRITE) {
74 			d->select = idata;
75 			if (idata <= 0x0d) {
76 				r = cpu->memory_rw(cpu, cpu->mem,
77 				    PCCMOS_MC146818_FAKE_ADDR, &b, 1,
78 				    MEM_WRITE, PHYSICAL);
79 			}
80 		} else
81 			odata = d->select;
82 	} else {
83 		if (d->select <= 0x0d) {
84 			if (writeflag == MEM_WRITE) {
85 				r = cpu->memory_rw(cpu, cpu->mem,
86 				    PCCMOS_MC146818_FAKE_ADDR + 1, &b, 1,
87 				    MEM_WRITE, PHYSICAL);
88 			} else {
89 				r = cpu->memory_rw(cpu, cpu->mem,
90 				    PCCMOS_MC146818_FAKE_ADDR + 1, &b, 1,
91 				    MEM_READ, PHYSICAL);
92 				odata = b;
93 			}
94 		} else {
95 			if (writeflag == MEM_WRITE)
96 				d->ram[d->select] = idata;
97 			else
98 				odata = d->ram[d->select];
99 		}
100 	}
101 
102 	if (r == 0)
103 		fatal("[ pccmos: memory_rw() error! ]\n");
104 
105 	if (writeflag == MEM_READ)
106 		memory_writemax64(cpu, data, len, odata);
107 
108 	return 1;
109 }
110 
111 
DEVINIT(pccmos)112 DEVINIT(pccmos)
113 {
114 	int type = MC146818_PC_CMOS, len = DEV_PCCMOS_LENGTH;
115 	struct pccmos_data *d;
116 
117 	CHECK_ALLOCATION(d = (struct pccmos_data *) malloc(sizeof(struct pccmos_data)));
118 	memset(d, 0, sizeof(struct pccmos_data));
119 
120 	switch (devinit->machine->machine_type) {
121 	case MACHINE_CATS:
122 	case MACHINE_NETWINDER:
123 		type = MC146818_CATS;
124 		d->ram[0x48] = 20;		/*  century  */
125 		len = DEV_PCCMOS_LENGTH * 2;
126 		break;
127 	case MACHINE_ALGOR:
128 		type = MC146818_ALGOR;
129 		break;
130 	case MACHINE_ARC:
131 		fatal("\nARC pccmos: TODO\n\n");
132 		type = MC146818_ALGOR;
133 		break;
134 	case MACHINE_EVBMIPS:
135 		/*  Malta etc.  */
136 		type = MC146818_ALGOR;
137 		break;
138 	case MACHINE_COBALT:
139 	case MACHINE_PREP:
140 	case MACHINE_MVMEPPC:
141 	case MACHINE_ALPHA:
142 	case MACHINE_IYONIX:	// TODO: not sure about exact type.
143 		break;
144 	default:fatal("devinit_pccmos(): unimplemented machine type"
145 		    " %i\n", devinit->machine->machine_type);
146 		exit(1);
147 	}
148 
149 	memory_device_register(devinit->machine->memory, devinit->name,
150 	    devinit->addr, len, dev_pccmos_access, (void *)d,
151 	    DM_DEFAULT, NULL);
152 
153 	dev_mc146818_init(devinit->machine, devinit->machine->memory,
154 	    PCCMOS_MC146818_FAKE_ADDR, devinit->interrupt_path, type, 1);
155 
156 	return 1;
157 }
158 
159