1 // Commander X16 Emulator
2 // Copyright (c) 2019 Michael Steil
3 // All rights reserved. License: 2-clause BSD
4 
5 #include <stdio.h>
6 #include <stdbool.h>
7 #include <time.h>
8 #include <stdlib.h>
9 #include "via.h"
10 #include "ps2.h"
11 #include "memory.h"
12 //XXX
13 #include "glue.h"
14 #include "joystick.h"
15 
16 //
17 // VIA#1
18 //
19 // PA0-7 RAM bank
20 // PB0-2 ROM bank
21 // PB3   IECATT0
22 // PB4   IECCLK0
23 // PB5   IECDAT0
24 // PB6   IECCLK
25 // PB7   IECDAT
26 // CB1   IECSRQ
27 
28 static uint8_t via1registers[16];
29 
30 void
via1_init()31 via1_init()
32 {
33 	srand(time(NULL));
34 
35 	// default banks are 0
36 	memory_set_ram_bank(0);
37 	memory_set_rom_bank(0);
38 }
39 
40 uint8_t
via1_read(uint8_t reg)41 via1_read(uint8_t reg)
42 {
43 	switch (reg) {
44 		case 0:
45 			return memory_get_rom_bank(); // PB: ROM bank, IEC
46 		case 1:
47 			return memory_get_ram_bank(); // PA: RAM bank
48 		case 4:
49 		case 5:
50 		case 8:
51 		case 9:
52 			// timer A and B: return random numbers for RND(0)
53 			// XXX TODO: these should be real timers :)
54 			return rand() & 0xff;
55 		default:
56 			return via1registers[reg];
57 	}
58 }
59 
60 void
via1_write(uint8_t reg,uint8_t value)61 via1_write(uint8_t reg, uint8_t value)
62 {
63 	via1registers[reg] = value;
64 	if (reg == 0) { // PB: ROM bank, IEC
65 		memory_set_rom_bank(value & 7);
66 		// TODO: IEC
67 	} else if (reg == 1) { // PA: RAM bank
68 		memory_set_ram_bank(value);
69 	} else {
70 		// TODO
71 	}
72 }
73 
74 //
75 // VIA#2
76 //
77 // PA0 PS/2 DAT
78 // PA1 PS/2 CLK
79 // PA2 LCD backlight
80 // PA3 NESJOY latch (for both joysticks)
81 // PA4 NESJOY joy1 data
82 // PA5 NESJOY joy1 CLK
83 // PA6 NESJOY joy2 data
84 // PA7 NESJOY joy2 CLK
85 
86 static uint8_t via2registers[16];
87 static uint8_t via2pb_in;
88 
89 void
via2_init()90 via2_init()
91 {
92 }
93 
94 uint8_t
via2_read(uint8_t reg)95 via2_read(uint8_t reg)
96 {
97 	// DDR=0 (input)  -> take input bit
98 	// DDR=1 (output) -> take output bit
99 	if (reg == 0) { // PB
100 		uint8_t value =
101 			(via2registers[2] & PS2_CLK_MASK ? 0 : ps2_port[1].clk_out << 1) |
102 			(via2registers[2] & PS2_DATA_MASK ? 0 : ps2_port[1].data_out);
103 		return value;
104 	} else if (reg == 1) { // PA
105 		uint8_t value =
106 			(via2registers[3] & PS2_CLK_MASK ? 0 : ps2_port[0].clk_out << 1) |
107 			(via2registers[3] & PS2_DATA_MASK ? 0 : ps2_port[0].data_out);
108 			value = value | (joystick1_data ? JOY_DATA1_MASK : 0) |
109 							(joystick2_data ? JOY_DATA2_MASK : 0);
110 		return value;
111 	} else {
112 		return via2registers[reg];
113 	}
114 }
115 
116 void
via2_write(uint8_t reg,uint8_t value)117 via2_write(uint8_t reg, uint8_t value)
118 {
119 	via2registers[reg] = value;
120 
121 	if (reg == 0 || reg == 2) {
122 		// PB
123 		ps2_port[1].clk_in = via2registers[2] & PS2_CLK_MASK ? via2registers[0] & PS2_CLK_MASK : 1;
124 		ps2_port[1].data_in = via2registers[2] & PS2_DATA_MASK ? via2registers[0] & PS2_DATA_MASK : 1;
125 	} else if (reg == 1 || reg == 3) {
126 		// PA
127 		ps2_port[0].clk_in = via2registers[3] & PS2_CLK_MASK ? via2registers[1] & PS2_CLK_MASK : 1;
128 		ps2_port[0].data_in = via2registers[3] & PS2_DATA_MASK ? via2registers[1] & PS2_DATA_MASK : 1;
129 		joystick_latch = via2registers[1] & JOY_LATCH_MASK;
130 		joystick_clock = via2registers[1] & JOY_CLK_MASK;
131 	}
132 }
133 
134 uint8_t
via2_pb_get_out()135 via2_pb_get_out()
136 {
137 	return via2registers[2] /* DDR  */ & via2registers[0]; /* PB */
138 }
139 
140 void
via2_pb_set_in(uint8_t value)141 via2_pb_set_in(uint8_t value)
142 {
143 	via2pb_in = value;
144 }
145 
146 void
via2_sr_set(uint8_t value)147 via2_sr_set(uint8_t value)
148 {
149 	via2registers[10] = value;
150 }
151