Fri, 18 Apr 2014 01:34:20 -0600
added RTC emulation (attempts to set the date are ignored, and the year is currently hardcoded to 1987 because UNIX PC SysV has a few Y2K bugs)
Makefile | file | annotate | diff | revisions | |
src/memory.c | file | annotate | diff | revisions | |
src/state.h | file | annotate | diff | revisions | |
src/tc8250.c | file | annotate | diff | revisions | |
src/tc8250.h | file | annotate | diff | revisions |
1.1 --- a/Makefile Fri Apr 18 01:26:01 2014 -0600 1.2 +++ b/Makefile Fri Apr 18 01:34:20 2014 -0600 1.3 @@ -118,7 +118,7 @@ 1.4 TARGET = freebee 1.5 1.6 # source files that produce object files 1.7 -SRC = main.c state.c memory.c wd279x.c wd2010.c keyboard.c 1.8 +SRC = main.c state.c memory.c wd279x.c wd2010.c keyboard.c tc8250.c 1.9 SRC += musashi/m68kcpu.c musashi/m68kdasm.c musashi/m68kops.c musashi/m68kopac.c musashi/m68kopdm.c musashi/m68kopnz.c 1.10 1.11 # source type - either "c" or "cpp" (C or C++)
2.1 --- a/src/memory.c Fri Apr 18 01:26:01 2014 -0600 2.2 +++ b/src/memory.c Fri Apr 18 01:34:20 2014 -0600 2.3 @@ -377,6 +377,13 @@ 2.4 case 0x070000: // Line Printer Status Register 2.5 break; 2.6 case 0x080000: // Real Time Clock 2.7 + ENFORCE_SIZE_W(bits, address, 16, "RTCWRITE"); 2.8 + /*printf("IoWrite RTCWRITE %x\n", data);*/ 2.9 + tc8250_set_chip_enable(&state.rtc_ctx, data & 0x8000); 2.10 + tc8250_set_address_latch_enable(&state.rtc_ctx, data & 0x4000); 2.11 + tc8250_set_write_enable(&state.rtc_ctx, data & 0x2000); 2.12 + tc8250_write_reg(&state.rtc_ctx, (data & 0x0F00) >> 8); 2.13 + handled = true; 2.14 break; 2.15 case 0x090000: // Phone registers 2.16 switch (address & 0x0FF000) { 2.17 @@ -693,7 +700,7 @@ 2.18 case 0x020000: // [ef][2a]xxxx ==> Miscellaneous Control Register 2 2.19 break; 2.20 case 0x030000: // [ef][3b]xxxx ==> Real Time Clock data bits 2.21 - break; 2.22 + return (tc8250_read_reg(&state.rtc_ctx)); 2.23 case 0x040000: // [ef][4c]xxxx ==> General Control Register 2.24 switch (address & 0x077000) { 2.25 case 0x040000: // [ef][4c][08]xxx ==> EE
3.1 --- a/src/state.h Fri Apr 18 01:26:01 2014 -0600 3.2 +++ b/src/state.h Fri Apr 18 01:34:20 2014 -0600 3.3 @@ -7,6 +7,8 @@ 3.4 #include "wd279x.h" 3.5 #include "wd2010.h" 3.6 #include "keyboard.h" 3.7 +#include "tc8250.h" 3.8 + 3.9 3.10 // Maximum size of the Boot PROMs. Must be a binary power of two. 3.11 #define ROM_SIZE 32768 3.12 @@ -90,6 +92,9 @@ 3.13 3.14 /// Keyboard controller context 3.15 KEYBOARD_STATE kbd; 3.16 + 3.17 + /// Real time clock context 3.18 + TC8250_CTX rtc_ctx; 3.19 } S_state; 3.20 3.21 // Global emulator state. Yes, I know global variables are evil, please don't
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 4.2 +++ b/src/tc8250.c Fri Apr 18 01:34:20 2014 -0600 4.3 @@ -0,0 +1,247 @@ 4.4 +#include <stdint.h> 4.5 +#include <stdbool.h> 4.6 +#include <malloc.h> 4.7 +#include <time.h> 4.8 +#include "tc8250.h" 4.9 + 4.10 +#ifndef TC8250_DEBUG 4.11 +#define NDEBUG 4.12 +#endif 4.13 +#include "utils.h" 4.14 + 4.15 +void tc8250_init(TC8250_CTX *ctx) 4.16 +{ 4.17 + ctx->chip_enable = false; 4.18 + ctx->address_latch_enable = false; 4.19 + ctx->write_enable = false; 4.20 + ctx->address = 0; 4.21 +} 4.22 + 4.23 +void tc8250_set_chip_enable(TC8250_CTX *ctx, bool enabled) 4.24 +{ 4.25 + LOG("tc8250_set_chip_enable %d\n", enabled); 4.26 + ctx->chip_enable = enabled; 4.27 +} 4.28 + 4.29 +void tc8250_set_address_latch_enable(TC8250_CTX *ctx, bool enabled) 4.30 +{ 4.31 + LOG("tc8250_set_address_latch_enable %d\n", enabled); 4.32 + ctx->address_latch_enable = enabled; 4.33 +} 4.34 + 4.35 +void tc8250_set_write_enable(TC8250_CTX *ctx, bool enabled) 4.36 +{ 4.37 + LOG("tc8250_set_write_enable %d\n", enabled); 4.38 + ctx->write_enable = enabled; 4.39 +} 4.40 + 4.41 +uint8_t get_second(TC8250_CTX *ctx) 4.42 +{ 4.43 + time_t t; 4.44 + struct tm g; 4.45 + uint8_t ret; 4.46 + t = time(NULL); 4.47 + gmtime_r(&t, &g); 4.48 + ret = g.tm_sec; 4.49 + return (ret); 4.50 +} 4.51 + 4.52 +uint8_t get_minute(TC8250_CTX *ctx) 4.53 +{ 4.54 + time_t t; 4.55 + struct tm g; 4.56 + uint8_t ret; 4.57 + t = time(NULL); 4.58 + gmtime_r(&t, &g); 4.59 + ret = g.tm_min; 4.60 + return (ret); 4.61 +} 4.62 + 4.63 +uint8_t get_hour(TC8250_CTX *ctx) 4.64 +{ 4.65 + time_t t; 4.66 + struct tm g; 4.67 + uint8_t ret; 4.68 + t = time(NULL); 4.69 + gmtime_r(&t, &g); 4.70 + ret = g.tm_hour; 4.71 + return (ret); 4.72 +} 4.73 + 4.74 +uint8_t get_day(TC8250_CTX *ctx) 4.75 +{ 4.76 + time_t t; 4.77 + struct tm g; 4.78 + uint8_t ret; 4.79 + t = time(NULL); 4.80 + gmtime_r(&t, &g); 4.81 + ret = g.tm_mday; 4.82 + return (ret); 4.83 +} 4.84 + 4.85 +uint8_t get_month(TC8250_CTX *ctx) 4.86 +{ 4.87 + time_t t; 4.88 + struct tm g; 4.89 + uint8_t ret; 4.90 + t = time(NULL); 4.91 + gmtime_r(&t, &g); 4.92 + ret = g.tm_mon; 4.93 + return (ret); 4.94 +} 4.95 + 4.96 +uint8_t get_year(TC8250_CTX *ctx) 4.97 +{ 4.98 + /*time_t t; 4.99 + struct tm g; 4.100 + uint8_t ret; 4.101 + t = time(NULL); 4.102 + gmtime_r(&t, &g); 4.103 + ret = g.tm_year; 4.104 + return (ret);*/ 4.105 + return (87); 4.106 +} 4.107 + 4.108 +uint8_t get_weekday(TC8250_CTX *ctx) 4.109 +{ 4.110 + time_t t; 4.111 + struct tm g; 4.112 + uint8_t ret; 4.113 + t = time(NULL); 4.114 + gmtime_r(&t, &g); 4.115 + ret = g.tm_wday; 4.116 + return (ret); 4.117 +} 4.118 + 4.119 +uint8_t tc8250_read_reg(TC8250_CTX *ctx) 4.120 +{ 4.121 + LOG("tc8250_read_reg %x\n", ctx->address); 4.122 + switch (ctx->address){ 4.123 + case ONE_SEC_DIGT: 4.124 + return (get_second(ctx) % 10); 4.125 + case TEN_SEC_DIGT: 4.126 + return (get_second(ctx) / 10); 4.127 + case ONE_MIN_DIGT: 4.128 + return (get_minute(ctx) % 10); 4.129 + case TEN_MIN_DIGT: 4.130 + return (get_minute(ctx) / 10); 4.131 + case ONE_HR_DIGT: 4.132 + return (get_hour(ctx) % 10); 4.133 + case TEN_HR_DIGT: 4.134 + return (get_hour(ctx) / 10); 4.135 + case ONE_DAY_DIGT: 4.136 + return (get_day(ctx) % 10); 4.137 + case TEN_DAY_DIGT: 4.138 + return (get_day(ctx) / 10); 4.139 + case ONE_MNTH_DIGT: 4.140 + return (get_month(ctx) % 10); 4.141 + case TEN_MNTH_DIGT: 4.142 + return (get_month(ctx) / 10); 4.143 + case ONE_YR_DIGT: 4.144 + return (get_year(ctx) % 10); 4.145 + case TEN_YR_DIGT: 4.146 + return (get_year(ctx) / 10); 4.147 + case WEEK_DAY: 4.148 + return (get_weekday(ctx) / 10); 4.149 + case TOUT_CONTROL: 4.150 + return (0); 4.151 + case PROTECT_KEY: 4.152 + return (0); 4.153 + case RTC_STATUS: 4.154 + return (0); 4.155 + default: 4.156 + return (0); 4.157 + } 4.158 +} 4.159 + 4.160 +void set_seconds(TC8250_CTX *ctx, uint8_t val) 4.161 +{ 4.162 +} 4.163 + 4.164 +void set_minutes(TC8250_CTX *ctx, uint8_t val) 4.165 +{ 4.166 +} 4.167 + 4.168 +void set_hours(TC8250_CTX *ctx, uint8_t val) 4.169 +{ 4.170 +} 4.171 + 4.172 +void set_days(TC8250_CTX *ctx, uint8_t val) 4.173 +{ 4.174 +} 4.175 + 4.176 +void set_months(TC8250_CTX *ctx, uint8_t val) 4.177 +{ 4.178 +} 4.179 + 4.180 +void set_years(TC8250_CTX *ctx, uint8_t val) 4.181 +{ 4.182 +} 4.183 + 4.184 +void set_weekday(TC8250_CTX *ctx, uint8_t val) 4.185 +{ 4.186 +} 4.187 + 4.188 +void tc8250_write_reg(TC8250_CTX *ctx, uint8_t val) 4.189 +{ 4.190 + LOG("tc8250_write_reg %x", val); 4.191 + if (ctx->address_latch_enable){ 4.192 + LOG(" address\n"); 4.193 + ctx->address = val; 4.194 + return; 4.195 + } 4.196 + if (ctx->chip_enable){ 4.197 + LOG(" %x\n", ctx->address); 4.198 + switch (ctx->address){ 4.199 + case ONE_SEC_DIGT: 4.200 + set_seconds(ctx, val % 10); 4.201 + break; 4.202 + case TEN_SEC_DIGT: 4.203 + set_seconds(ctx, val % 10 * 10); 4.204 + break; 4.205 + case ONE_MIN_DIGT: 4.206 + set_minutes(ctx, val % 10); 4.207 + break; 4.208 + case TEN_MIN_DIGT: 4.209 + set_minutes(ctx, val % 10 * 10); 4.210 + break; 4.211 + case ONE_HR_DIGT: 4.212 + set_hours(ctx, val % 10); 4.213 + break; 4.214 + case TEN_HR_DIGT: 4.215 + set_hours(ctx, val % 10 * 10); 4.216 + break; 4.217 + case ONE_DAY_DIGT: 4.218 + set_days(ctx, val % 10); 4.219 + break; 4.220 + case TEN_DAY_DIGT: 4.221 + set_days(ctx, val % 10 * 10); 4.222 + break; 4.223 + case ONE_MNTH_DIGT: 4.224 + set_months(ctx, val % 10); 4.225 + break; 4.226 + case TEN_MNTH_DIGT: 4.227 + set_months(ctx, val % 10 * 10); 4.228 + break; 4.229 + case ONE_YR_DIGT: 4.230 + set_years(ctx, val % 10); 4.231 + break; 4.232 + case TEN_YR_DIGT: 4.233 + set_years(ctx, val % 10 * 10); 4.234 + break; 4.235 + case WEEK_DAY: 4.236 + set_weekday(ctx, val % 10); 4.237 + break; 4.238 + case TOUT_CONTROL: 4.239 + break; 4.240 + case PROTECT_KEY: 4.241 + break; 4.242 + case RTC_STATUS: 4.243 + break; 4.244 + default: 4.245 + break; 4.246 + } 4.247 + }else{ 4.248 + LOG("\n"); 4.249 + } 4.250 +}
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/src/tc8250.h Fri Apr 18 01:34:20 2014 -0600 5.3 @@ -0,0 +1,48 @@ 5.4 +#ifndef _TC8250_H 5.5 +#define _TC8250_H 5.6 + 5.7 +#include <stdbool.h> 5.8 +#include <stddef.h> 5.9 +#include <stdint.h> 5.10 +#include <stdio.h> 5.11 + 5.12 +typedef struct { 5.13 + bool chip_enable; 5.14 + bool address_latch_enable; 5.15 + bool write_enable; 5.16 + uint8_t address; 5.17 + uint8_t seconds_offset; 5.18 + uint8_t minutes_offset; 5.19 + uint8_t hours_offset; 5.20 + uint8_t days_offset; 5.21 + uint8_t months_offset; 5.22 + uint8_t years_offset; 5.23 + uint8_t weekday_offset; 5.24 +} TC8250_CTX; 5.25 + 5.26 +void tc8250_init(TC8250_CTX *ctx); 5.27 +void tc8250_set_chip_enable(TC8250_CTX *ctx, bool enabled); 5.28 +void tc8250_set_address_latch_enable(TC8250_CTX *ctx, bool enabled); 5.29 +void tc8250_set_write_enable(TC8250_CTX *ctx, bool enabled); 5.30 +uint8_t tc8250_read_reg(TC8250_CTX *ctx); 5.31 +void tc8250_write_reg(TC8250_CTX *ctx, uint8_t val); 5.32 + 5.33 +enum { 5.34 + ONE_SEC_DIGT = 0x0, /* 1 sec digit */ 5.35 + TEN_SEC_DIGT = 0x1, /* 10 sec digit */ 5.36 + ONE_MIN_DIGT = 0x2, /* 1 minute digit */ 5.37 + TEN_MIN_DIGT = 0x3, /* 10 minutes digit */ 5.38 + ONE_HR_DIGT = 0x4, /* 1 hour digit */ 5.39 + TEN_HR_DIGT = 0x5, /* 10 hours digit */ 5.40 + ONE_DAY_DIGT = 0x6, /* 1 day digit */ 5.41 + TEN_DAY_DIGT = 0x7, /* 10 days digit */ 5.42 + ONE_MNTH_DIGT = 0x8, /* 1 month digit */ 5.43 + TEN_MNTH_DIGT = 0x9, /* 10 month digit */ 5.44 + ONE_YR_DIGT = 0xa, /* 1 year digit */ 5.45 + TEN_YR_DIGT = 0xb, /* 10 year digit */ 5.46 + WEEK_DAY = 0xc, /* day of the week */ 5.47 + TOUT_CONTROL = 0xd, /* Tout control */ 5.48 + PROTECT_KEY = 0xe, /* protection key */ 5.49 + RTC_STATUS = 0xf /* real time clock status */ 5.50 +}; 5.51 +#endif