BBC Basic in Z80 emulation on the mbed, USB serial terminal output only. LOAD and SAVE work on the local file system but there is no error signalling.
main.cpp@0:806c2f2a7d47, 2011-06-29 (annotated)
- Committer:
- gertk
- Date:
- Wed Jun 29 14:25:56 2011 +0000
- Revision:
- 0:806c2f2a7d47
preliminary version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
gertk | 0:806c2f2a7d47 | 1 | /* BBC Basic emulator on NXP mbed by Gert van der Knokke |
gertk | 0:806c2f2a7d47 | 2 | * Emulation of the Z80 CPU |
gertk | 0:806c2f2a7d47 | 3 | * The z80 emulator is heavily modified by me (Gert) |
gertk | 0:806c2f2a7d47 | 4 | * original Copyright (C) 1994 Ian Collier. |
gertk | 0:806c2f2a7d47 | 5 | * |
gertk | 0:806c2f2a7d47 | 6 | * This program is free software; you can redistribute it and/or modify |
gertk | 0:806c2f2a7d47 | 7 | * it under the terms of the GNU General Public License as published by |
gertk | 0:806c2f2a7d47 | 8 | * the Free Software Foundation; either version 2 of the License, or |
gertk | 0:806c2f2a7d47 | 9 | * (at your option) any later version. |
gertk | 0:806c2f2a7d47 | 10 | * |
gertk | 0:806c2f2a7d47 | 11 | * This program is distributed in the hope that it will be useful, |
gertk | 0:806c2f2a7d47 | 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
gertk | 0:806c2f2a7d47 | 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
gertk | 0:806c2f2a7d47 | 14 | * GNU General Public License for more details. |
gertk | 0:806c2f2a7d47 | 15 | * |
gertk | 0:806c2f2a7d47 | 16 | * You should have received a copy of the GNU General Public License |
gertk | 0:806c2f2a7d47 | 17 | * along with this program; if not, write to the Free Software |
gertk | 0:806c2f2a7d47 | 18 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. |
gertk | 0:806c2f2a7d47 | 19 | */ |
gertk | 0:806c2f2a7d47 | 20 | |
gertk | 0:806c2f2a7d47 | 21 | #include "mbed.h" |
gertk | 0:806c2f2a7d47 | 22 | #include "module.h" |
gertk | 0:806c2f2a7d47 | 23 | #include "z80.h" |
gertk | 0:806c2f2a7d47 | 24 | |
gertk | 0:806c2f2a7d47 | 25 | #define DEBUG false |
gertk | 0:806c2f2a7d47 | 26 | |
gertk | 0:806c2f2a7d47 | 27 | // define serial port for debug |
gertk | 0:806c2f2a7d47 | 28 | Serial linktopc(USBTX,USBRX); |
gertk | 0:806c2f2a7d47 | 29 | |
gertk | 0:806c2f2a7d47 | 30 | |
gertk | 0:806c2f2a7d47 | 31 | // VDU queue |
gertk | 0:806c2f2a7d47 | 32 | unsigned char vdu_queue[256]; // a somewhat large queue |
gertk | 0:806c2f2a7d47 | 33 | unsigned char queue_bytes=0; // vdu queue pointer |
gertk | 0:806c2f2a7d47 | 34 | unsigned char oldchar; // which VDU function needs the queue |
gertk | 0:806c2f2a7d47 | 35 | |
gertk | 0:806c2f2a7d47 | 36 | volatile unsigned char flag,oldy=0; |
gertk | 0:806c2f2a7d47 | 37 | |
gertk | 0:806c2f2a7d47 | 38 | |
gertk | 0:806c2f2a7d47 | 39 | int background_color; // for clear screen |
gertk | 0:806c2f2a7d47 | 40 | int cursor_xpos; |
gertk | 0:806c2f2a7d47 | 41 | int cursor_ypos; |
gertk | 0:806c2f2a7d47 | 42 | int last_line_processed; |
gertk | 0:806c2f2a7d47 | 43 | int previous_line_found; |
gertk | 0:806c2f2a7d47 | 44 | |
gertk | 0:806c2f2a7d47 | 45 | int current_background_color; |
gertk | 0:806c2f2a7d47 | 46 | int current_text_color; |
gertk | 0:806c2f2a7d47 | 47 | |
gertk | 0:806c2f2a7d47 | 48 | |
gertk | 0:806c2f2a7d47 | 49 | // prepare mbed storage for local use |
gertk | 0:806c2f2a7d47 | 50 | LocalFileSystem local("local"); // Create the local filesystem under the name "local" |
gertk | 0:806c2f2a7d47 | 51 | |
gertk | 0:806c2f2a7d47 | 52 | // clear the screen |
gertk | 0:806c2f2a7d47 | 53 | void cls() { |
gertk | 0:806c2f2a7d47 | 54 | putchar(0x0c); |
gertk | 0:806c2f2a7d47 | 55 | } |
gertk | 0:806c2f2a7d47 | 56 | |
gertk | 0:806c2f2a7d47 | 57 | // dummy function |
gertk | 0:806c2f2a7d47 | 58 | void set_cursor_position() { |
gertk | 0:806c2f2a7d47 | 59 | } |
gertk | 0:806c2f2a7d47 | 60 | |
gertk | 0:806c2f2a7d47 | 61 | // home cursor |
gertk | 0:806c2f2a7d47 | 62 | void home_cursor() { |
gertk | 0:806c2f2a7d47 | 63 | cursor_xpos=0x00; // ypos |
gertk | 0:806c2f2a7d47 | 64 | cursor_ypos=0x00; // xpos |
gertk | 0:806c2f2a7d47 | 65 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 66 | } |
gertk | 0:806c2f2a7d47 | 67 | |
gertk | 0:806c2f2a7d47 | 68 | // prepare the screen |
gertk | 0:806c2f2a7d47 | 69 | void init_screen() { |
gertk | 0:806c2f2a7d47 | 70 | current_background_color=0; // set initial background color |
gertk | 0:806c2f2a7d47 | 71 | current_text_color=7; // initial text color attributes |
gertk | 0:806c2f2a7d47 | 72 | cls(); |
gertk | 0:806c2f2a7d47 | 73 | home_cursor(); |
gertk | 0:806c2f2a7d47 | 74 | } |
gertk | 0:806c2f2a7d47 | 75 | |
gertk | 0:806c2f2a7d47 | 76 | // handle VDU calls after all bytes are in queue |
gertk | 0:806c2f2a7d47 | 77 | // Note! queue is working front to back (255 is first, 0 is last) |
gertk | 0:806c2f2a7d47 | 78 | void do_handle_queue(unsigned char code) { |
gertk | 0:806c2f2a7d47 | 79 | switch (code) { |
gertk | 0:806c2f2a7d47 | 80 | case 0x11: // select text color |
gertk | 0:806c2f2a7d47 | 81 | current_text_color=vdu_queue[255]; |
gertk | 0:806c2f2a7d47 | 82 | break; |
gertk | 0:806c2f2a7d47 | 83 | case 0x16: // Mode |
gertk | 0:806c2f2a7d47 | 84 | current_text_color=7; |
gertk | 0:806c2f2a7d47 | 85 | current_background_color=0; |
gertk | 0:806c2f2a7d47 | 86 | init_screen(); |
gertk | 0:806c2f2a7d47 | 87 | home_cursor(); |
gertk | 0:806c2f2a7d47 | 88 | break; |
gertk | 0:806c2f2a7d47 | 89 | case 0x17: // define character n |
gertk | 0:806c2f2a7d47 | 90 | break; |
gertk | 0:806c2f2a7d47 | 91 | case 0x1f: // move cursor to x,y |
gertk | 0:806c2f2a7d47 | 92 | cursor_xpos=vdu_queue[254]; |
gertk | 0:806c2f2a7d47 | 93 | cursor_ypos=vdu_queue[255]; |
gertk | 0:806c2f2a7d47 | 94 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 95 | break; |
gertk | 0:806c2f2a7d47 | 96 | } |
gertk | 0:806c2f2a7d47 | 97 | } |
gertk | 0:806c2f2a7d47 | 98 | |
gertk | 0:806c2f2a7d47 | 99 | // VDU OSWRCHR |
gertk | 0:806c2f2a7d47 | 100 | // this routine evaluates the stream characters |
gertk | 0:806c2f2a7d47 | 101 | // and prepares the queue if needed |
gertk | 0:806c2f2a7d47 | 102 | void printchar(unsigned char ch) { |
gertk | 0:806c2f2a7d47 | 103 | |
gertk | 0:806c2f2a7d47 | 104 | // do we need more queue bytes ? |
gertk | 0:806c2f2a7d47 | 105 | if (queue_bytes) { |
gertk | 0:806c2f2a7d47 | 106 | vdu_queue[queue_bytes++]=ch; |
gertk | 0:806c2f2a7d47 | 107 | // all bytes in queue, now handle the call |
gertk | 0:806c2f2a7d47 | 108 | if (queue_bytes==0) |
gertk | 0:806c2f2a7d47 | 109 | do_handle_queue(oldchar); |
gertk | 0:806c2f2a7d47 | 110 | |
gertk | 0:806c2f2a7d47 | 111 | } else { |
gertk | 0:806c2f2a7d47 | 112 | |
gertk | 0:806c2f2a7d47 | 113 | switch (ch) { |
gertk | 0:806c2f2a7d47 | 114 | case 0x00: // NULL |
gertk | 0:806c2f2a7d47 | 115 | break; |
gertk | 0:806c2f2a7d47 | 116 | case 0x08: // CURSOR LEFT |
gertk | 0:806c2f2a7d47 | 117 | putchar(0x08); |
gertk | 0:806c2f2a7d47 | 118 | if (cursor_xpos>0) { |
gertk | 0:806c2f2a7d47 | 119 | cursor_xpos--; |
gertk | 0:806c2f2a7d47 | 120 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 121 | } |
gertk | 0:806c2f2a7d47 | 122 | break; |
gertk | 0:806c2f2a7d47 | 123 | case 0x09: // CURSOR RIGHT |
gertk | 0:806c2f2a7d47 | 124 | if (cursor_xpos<39) { |
gertk | 0:806c2f2a7d47 | 125 | cursor_xpos++; |
gertk | 0:806c2f2a7d47 | 126 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 127 | } |
gertk | 0:806c2f2a7d47 | 128 | break; |
gertk | 0:806c2f2a7d47 | 129 | case 0x0a: // CURSOR DOWN |
gertk | 0:806c2f2a7d47 | 130 | if (cursor_ypos<23) { |
gertk | 0:806c2f2a7d47 | 131 | cursor_ypos++; |
gertk | 0:806c2f2a7d47 | 132 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 133 | } else { |
gertk | 0:806c2f2a7d47 | 134 | cursor_ypos=23; |
gertk | 0:806c2f2a7d47 | 135 | } |
gertk | 0:806c2f2a7d47 | 136 | break; |
gertk | 0:806c2f2a7d47 | 137 | case 0x0b: // CURSOR UP |
gertk | 0:806c2f2a7d47 | 138 | cursor_ypos++; |
gertk | 0:806c2f2a7d47 | 139 | if (cursor_ypos>0) { |
gertk | 0:806c2f2a7d47 | 140 | cursor_ypos--; |
gertk | 0:806c2f2a7d47 | 141 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 142 | } else { |
gertk | 0:806c2f2a7d47 | 143 | cursor_ypos=0; |
gertk | 0:806c2f2a7d47 | 144 | } |
gertk | 0:806c2f2a7d47 | 145 | break; |
gertk | 0:806c2f2a7d47 | 146 | case 0x0d: // Carriage Return |
gertk | 0:806c2f2a7d47 | 147 | cursor_xpos=0; |
gertk | 0:806c2f2a7d47 | 148 | putchar(0x0d); |
gertk | 0:806c2f2a7d47 | 149 | putchar(0x0a); |
gertk | 0:806c2f2a7d47 | 150 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 151 | break; |
gertk | 0:806c2f2a7d47 | 152 | case 0x0c: // CLEAR TEXT WINDOW |
gertk | 0:806c2f2a7d47 | 153 | case 0x10: // CLEAR GRAPHIC WINDOW |
gertk | 0:806c2f2a7d47 | 154 | cls(); |
gertk | 0:806c2f2a7d47 | 155 | cursor_xpos=0; |
gertk | 0:806c2f2a7d47 | 156 | cursor_ypos=0; |
gertk | 0:806c2f2a7d47 | 157 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 158 | break; |
gertk | 0:806c2f2a7d47 | 159 | case 0x11: // set TEXT color |
gertk | 0:806c2f2a7d47 | 160 | oldchar=ch; // this was the code of the initial call |
gertk | 0:806c2f2a7d47 | 161 | queue_bytes=256-1; // for this call we need one more byte |
gertk | 0:806c2f2a7d47 | 162 | break; |
gertk | 0:806c2f2a7d47 | 163 | case 0x14: // reset colors |
gertk | 0:806c2f2a7d47 | 164 | current_text_color=7; |
gertk | 0:806c2f2a7d47 | 165 | current_background_color=0; |
gertk | 0:806c2f2a7d47 | 166 | break; |
gertk | 0:806c2f2a7d47 | 167 | case 0x16: // MODE select |
gertk | 0:806c2f2a7d47 | 168 | oldchar=ch; |
gertk | 0:806c2f2a7d47 | 169 | queue_bytes=256-1; |
gertk | 0:806c2f2a7d47 | 170 | break; |
gertk | 0:806c2f2a7d47 | 171 | case 0x17: // define character n |
gertk | 0:806c2f2a7d47 | 172 | break; |
gertk | 0:806c2f2a7d47 | 173 | case 0x1e: |
gertk | 0:806c2f2a7d47 | 174 | cursor_xpos=0; |
gertk | 0:806c2f2a7d47 | 175 | cursor_ypos=0; |
gertk | 0:806c2f2a7d47 | 176 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 177 | break; |
gertk | 0:806c2f2a7d47 | 178 | case 0x1f: // set cursor to position X,Y |
gertk | 0:806c2f2a7d47 | 179 | oldchar=ch; // this was the code of the initial call |
gertk | 0:806c2f2a7d47 | 180 | queue_bytes=256-2; // for this call we need two more bytes |
gertk | 0:806c2f2a7d47 | 181 | break; |
gertk | 0:806c2f2a7d47 | 182 | // all else is put on screen literally |
gertk | 0:806c2f2a7d47 | 183 | default: |
gertk | 0:806c2f2a7d47 | 184 | putchar(ch); |
gertk | 0:806c2f2a7d47 | 185 | break; |
gertk | 0:806c2f2a7d47 | 186 | } |
gertk | 0:806c2f2a7d47 | 187 | } |
gertk | 0:806c2f2a7d47 | 188 | } |
gertk | 0:806c2f2a7d47 | 189 | |
gertk | 0:806c2f2a7d47 | 190 | |
gertk | 0:806c2f2a7d47 | 191 | void init_ramtop() { |
gertk | 0:806c2f2a7d47 | 192 | |
gertk | 0:806c2f2a7d47 | 193 | |
gertk | 0:806c2f2a7d47 | 194 | // set all MOS calls to illegal opcode 0xed55 |
gertk | 0:806c2f2a7d47 | 195 | // that code is trapped by a mbed routine |
gertk | 0:806c2f2a7d47 | 196 | wrmem(OSWRCH,0xed); |
gertk | 0:806c2f2a7d47 | 197 | wrmem(OSWRCH+1,0x55); |
gertk | 0:806c2f2a7d47 | 198 | |
gertk | 0:806c2f2a7d47 | 199 | wrmem(OSWORD,0xed); |
gertk | 0:806c2f2a7d47 | 200 | wrmem(OSWORD+1,0x55); |
gertk | 0:806c2f2a7d47 | 201 | |
gertk | 0:806c2f2a7d47 | 202 | wrmem(OSBYTE,0xed); |
gertk | 0:806c2f2a7d47 | 203 | wrmem(OSBYTE+1,0x55); |
gertk | 0:806c2f2a7d47 | 204 | |
gertk | 0:806c2f2a7d47 | 205 | wrmem(OSRDCH,0xed); |
gertk | 0:806c2f2a7d47 | 206 | wrmem(OSRDCH+1,0x55); |
gertk | 0:806c2f2a7d47 | 207 | |
gertk | 0:806c2f2a7d47 | 208 | wrmem(OSNEWL,0xed); |
gertk | 0:806c2f2a7d47 | 209 | wrmem(OSNEWL+1,0x55); |
gertk | 0:806c2f2a7d47 | 210 | |
gertk | 0:806c2f2a7d47 | 211 | wrmem(OSASCI,0xed); |
gertk | 0:806c2f2a7d47 | 212 | wrmem(OSASCI+1,0x55); |
gertk | 0:806c2f2a7d47 | 213 | |
gertk | 0:806c2f2a7d47 | 214 | wrmem(OSRDCH,0xed); |
gertk | 0:806c2f2a7d47 | 215 | wrmem(OSRDCH+1,0x55); |
gertk | 0:806c2f2a7d47 | 216 | |
gertk | 0:806c2f2a7d47 | 217 | wrmem(MAINVDU,0xed); |
gertk | 0:806c2f2a7d47 | 218 | wrmem(MAINVDU+1,0x55); |
gertk | 0:806c2f2a7d47 | 219 | |
gertk | 0:806c2f2a7d47 | 220 | wrmem(GSINIT,0xed); |
gertk | 0:806c2f2a7d47 | 221 | wrmem(GSINIT+1,0x55); |
gertk | 0:806c2f2a7d47 | 222 | |
gertk | 0:806c2f2a7d47 | 223 | wrmem(GSREAD,0xed); |
gertk | 0:806c2f2a7d47 | 224 | wrmem(GSREAD+1,0x55); |
gertk | 0:806c2f2a7d47 | 225 | |
gertk | 0:806c2f2a7d47 | 226 | wrmem(OSRDRM,0xed); |
gertk | 0:806c2f2a7d47 | 227 | wrmem(OSRDRM+1,0x55); |
gertk | 0:806c2f2a7d47 | 228 | |
gertk | 0:806c2f2a7d47 | 229 | wrmem(OSEVEN,0xed); |
gertk | 0:806c2f2a7d47 | 230 | wrmem(OSEVEN+1,0x55); |
gertk | 0:806c2f2a7d47 | 231 | |
gertk | 0:806c2f2a7d47 | 232 | wrmem(OSCLI,0xed); |
gertk | 0:806c2f2a7d47 | 233 | wrmem(OSCLI+1,0x55); |
gertk | 0:806c2f2a7d47 | 234 | |
gertk | 0:806c2f2a7d47 | 235 | wrmem(OSFILE,0xed); |
gertk | 0:806c2f2a7d47 | 236 | wrmem(OSFILE+1,0x55); |
gertk | 0:806c2f2a7d47 | 237 | |
gertk | 0:806c2f2a7d47 | 238 | wrmem(CMDPTR,0xf0); // pointer to CR terminated string (auto start filename) |
gertk | 0:806c2f2a7d47 | 239 | wrmem(CMDPTR+1,0x00); // it is set here to 0x00f0 |
gertk | 0:806c2f2a7d47 | 240 | |
gertk | 0:806c2f2a7d47 | 241 | wrmem(BRKV,0x00); // break vector |
gertk | 0:806c2f2a7d47 | 242 | wrmem(BRKV+1,0x00); |
gertk | 0:806c2f2a7d47 | 243 | |
gertk | 0:806c2f2a7d47 | 244 | wrmem(FAULT,0x38); // fault vector |
gertk | 0:806c2f2a7d47 | 245 | wrmem(FAULT+1,0x00); |
gertk | 0:806c2f2a7d47 | 246 | } |
gertk | 0:806c2f2a7d47 | 247 | |
gertk | 0:806c2f2a7d47 | 248 | unsigned char getkey() { |
gertk | 0:806c2f2a7d47 | 249 | unsigned char key=0x00; |
gertk | 0:806c2f2a7d47 | 250 | if (linktopc.readable()) // get USB status |
gertk | 0:806c2f2a7d47 | 251 | key=linktopc.getc(); // get ASCII key |
gertk | 0:806c2f2a7d47 | 252 | return key; |
gertk | 0:806c2f2a7d47 | 253 | } |
gertk | 0:806c2f2a7d47 | 254 | |
gertk | 0:806c2f2a7d47 | 255 | // crude getline routine |
gertk | 0:806c2f2a7d47 | 256 | void mygets(int ad,int max,unsigned char minasc,unsigned char maxasc) { |
gertk | 0:806c2f2a7d47 | 257 | int n=0; |
gertk | 0:806c2f2a7d47 | 258 | int key=0; |
gertk | 0:806c2f2a7d47 | 259 | |
gertk | 0:806c2f2a7d47 | 260 | bool eflag=1; |
gertk | 0:806c2f2a7d47 | 261 | |
gertk | 0:806c2f2a7d47 | 262 | // show cursor |
gertk | 0:806c2f2a7d47 | 263 | set_cursor_position(); |
gertk | 0:806c2f2a7d47 | 264 | |
gertk | 0:806c2f2a7d47 | 265 | while (eflag) { |
gertk | 0:806c2f2a7d47 | 266 | // key=getkey(); |
gertk | 0:806c2f2a7d47 | 267 | #if !DEBUG |
gertk | 0:806c2f2a7d47 | 268 | // USB serial data ? then override key (only when NOT in debug mode) |
gertk | 0:806c2f2a7d47 | 269 | if (linktopc.readable()) // get USB status |
gertk | 0:806c2f2a7d47 | 270 | key=linktopc.getc(); // get ASCII key code |
gertk | 0:806c2f2a7d47 | 271 | else key=0; |
gertk | 0:806c2f2a7d47 | 272 | // key=getchar(); // BLOCKING MODE |
gertk | 0:806c2f2a7d47 | 273 | #endif |
gertk | 0:806c2f2a7d47 | 274 | |
gertk | 0:806c2f2a7d47 | 275 | if (key) // printf("got key code: %02x\n\r",key); |
gertk | 0:806c2f2a7d47 | 276 | |
gertk | 0:806c2f2a7d47 | 277 | // only ASCII should arrive here |
gertk | 0:806c2f2a7d47 | 278 | switch (key) { |
gertk | 0:806c2f2a7d47 | 279 | case 0x00: // no key |
gertk | 0:806c2f2a7d47 | 280 | break; |
gertk | 0:806c2f2a7d47 | 281 | case 0x0d: // Enter or Return |
gertk | 0:806c2f2a7d47 | 282 | wrmem(ad+n,key); |
gertk | 0:806c2f2a7d47 | 283 | h=n; |
gertk | 0:806c2f2a7d47 | 284 | // clear carry flag |
gertk | 0:806c2f2a7d47 | 285 | anda(a); // z80 way of clearing carry... |
gertk | 0:806c2f2a7d47 | 286 | eflag=0; // terminate the loop |
gertk | 0:806c2f2a7d47 | 287 | printchar(key); |
gertk | 0:806c2f2a7d47 | 288 | printchar(0x0a); |
gertk | 0:806c2f2a7d47 | 289 | break; |
gertk | 0:806c2f2a7d47 | 290 | case 0x1b: // Escape |
gertk | 0:806c2f2a7d47 | 291 | wrmem(ad+n,key); |
gertk | 0:806c2f2a7d47 | 292 | // set carry flag |
gertk | 0:806c2f2a7d47 | 293 | f=(f&0xc4)|1|(a&0x28); |
gertk | 0:806c2f2a7d47 | 294 | eflag=0; |
gertk | 0:806c2f2a7d47 | 295 | h=n; |
gertk | 0:806c2f2a7d47 | 296 | break; |
gertk | 0:806c2f2a7d47 | 297 | case 0x15: // CTRL-U (clear input) |
gertk | 0:806c2f2a7d47 | 298 | while (n) { |
gertk | 0:806c2f2a7d47 | 299 | |
gertk | 0:806c2f2a7d47 | 300 | printchar(0x08); |
gertk | 0:806c2f2a7d47 | 301 | printchar(0x20); |
gertk | 0:806c2f2a7d47 | 302 | printchar(0x08); |
gertk | 0:806c2f2a7d47 | 303 | n--; |
gertk | 0:806c2f2a7d47 | 304 | } |
gertk | 0:806c2f2a7d47 | 305 | wrmem(ad,0x0d); |
gertk | 0:806c2f2a7d47 | 306 | break; |
gertk | 0:806c2f2a7d47 | 307 | case 0x7f: // DELETE |
gertk | 0:806c2f2a7d47 | 308 | if (n) { |
gertk | 0:806c2f2a7d47 | 309 | n--; |
gertk | 0:806c2f2a7d47 | 310 | printchar(0x08); // cursor left |
gertk | 0:806c2f2a7d47 | 311 | printchar(0x20); // delete character by printing a space |
gertk | 0:806c2f2a7d47 | 312 | printchar(0x08); // cursor left |
gertk | 0:806c2f2a7d47 | 313 | wrmem(ad+n,0x20); // overwrite with space |
gertk | 0:806c2f2a7d47 | 314 | } |
gertk | 0:806c2f2a7d47 | 315 | break; |
gertk | 0:806c2f2a7d47 | 316 | default: // all else |
gertk | 0:806c2f2a7d47 | 317 | // keep within maximum lenght and given ascii limits |
gertk | 0:806c2f2a7d47 | 318 | if ((key>=minasc) && (key<=maxasc) && n<max) { |
gertk | 0:806c2f2a7d47 | 319 | wrmem(ad+n,key); |
gertk | 0:806c2f2a7d47 | 320 | n++; |
gertk | 0:806c2f2a7d47 | 321 | printchar(key); |
gertk | 0:806c2f2a7d47 | 322 | } |
gertk | 0:806c2f2a7d47 | 323 | break; |
gertk | 0:806c2f2a7d47 | 324 | } |
gertk | 0:806c2f2a7d47 | 325 | } |
gertk | 0:806c2f2a7d47 | 326 | } |
gertk | 0:806c2f2a7d47 | 327 | |
gertk | 0:806c2f2a7d47 | 328 | |
gertk | 0:806c2f2a7d47 | 329 | // OSWORD |
gertk | 0:806c2f2a7d47 | 330 | void do_osword() { |
gertk | 0:806c2f2a7d47 | 331 | int ad,n; |
gertk | 0:806c2f2a7d47 | 332 | char buf[40]; |
gertk | 0:806c2f2a7d47 | 333 | time_t seconds; |
gertk | 0:806c2f2a7d47 | 334 | |
gertk | 0:806c2f2a7d47 | 335 | // printf("OSWORD called with PC=%04x A=%02x HL=%02x%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 336 | switch (a) { |
gertk | 0:806c2f2a7d47 | 337 | |
gertk | 0:806c2f2a7d47 | 338 | case 0x00: // get a line from the keyboard/input channel |
gertk | 0:806c2f2a7d47 | 339 | ad=(h<<8)+l; |
gertk | 0:806c2f2a7d47 | 340 | // printf("Control block:\n\r"); |
gertk | 0:806c2f2a7d47 | 341 | // printf("buffer address %02x%02x\n\r",rdmem(ad+1),rdmem(ad)); |
gertk | 0:806c2f2a7d47 | 342 | // printf("maximum length: %d\n\r",rdmem(ad+2)); |
gertk | 0:806c2f2a7d47 | 343 | // printf("minimum ASCII value %d\n\r",rdmem(ad+3)); |
gertk | 0:806c2f2a7d47 | 344 | // printf("maximum ASCII value %d\n\r",rdmem(ad+4)); |
gertk | 0:806c2f2a7d47 | 345 | |
gertk | 0:806c2f2a7d47 | 346 | mygets((rdmem(ad+1)<<8)+rdmem(ad),rdmem(ad+2),rdmem(ad+3),rdmem(ad+4)); |
gertk | 0:806c2f2a7d47 | 347 | |
gertk | 0:806c2f2a7d47 | 348 | break; |
gertk | 0:806c2f2a7d47 | 349 | case 0x01: // read systemclock (long integer) |
gertk | 0:806c2f2a7d47 | 350 | break; |
gertk | 0:806c2f2a7d47 | 351 | case 0x02: // write systemclock (long integer) |
gertk | 0:806c2f2a7d47 | 352 | break; |
gertk | 0:806c2f2a7d47 | 353 | case 0x07: // emit a sound from the sound library (0-7) |
gertk | 0:806c2f2a7d47 | 354 | break; |
gertk | 0:806c2f2a7d47 | 355 | case 0x0e: // read TIME$ (not present in original BBC Basic) |
gertk | 0:806c2f2a7d47 | 356 | ad=hl; // get pointer to function number |
gertk | 0:806c2f2a7d47 | 357 | switch (rdmem(hl)) { // select function number |
gertk | 0:806c2f2a7d47 | 358 | case 0: // return time string |
gertk | 0:806c2f2a7d47 | 359 | seconds = time(NULL); // get current time from mbed RTC |
gertk | 0:806c2f2a7d47 | 360 | strftime(buf,40, "%a,%d %m %Y.%H:%M:%S\r", localtime(&seconds)); // write to temporary buffer |
gertk | 0:806c2f2a7d47 | 361 | n=0; |
gertk | 0:806c2f2a7d47 | 362 | while (buf[n]) wrmem(ad++,buf[n++]); // copy to pointer from HL |
gertk | 0:806c2f2a7d47 | 363 | break; |
gertk | 0:806c2f2a7d47 | 364 | case 1: // return BCD values of clock |
gertk | 0:806c2f2a7d47 | 365 | // On exit: |
gertk | 0:806c2f2a7d47 | 366 | // XY?0=year (&00-&99) |
gertk | 0:806c2f2a7d47 | 367 | // XY?1=month (&01-&12) |
gertk | 0:806c2f2a7d47 | 368 | // XY?2=date (&01-&31) |
gertk | 0:806c2f2a7d47 | 369 | // XY?3=day of week (&01-&07, Sun-Sat) |
gertk | 0:806c2f2a7d47 | 370 | // XY?4=hours (&00-&23) |
gertk | 0:806c2f2a7d47 | 371 | // XY?5=minutes (&00-&59) |
gertk | 0:806c2f2a7d47 | 372 | // XY?6=seconds (&00-&59). |
gertk | 0:806c2f2a7d47 | 373 | // |
gertk | 0:806c2f2a7d47 | 374 | // A year value of &80-&99 represents 1980-1999, a value of |
gertk | 0:806c2f2a7d47 | 375 | // &00-&79 represents 2000-2079. |
gertk | 0:806c2f2a7d47 | 376 | // |
gertk | 0:806c2f2a7d47 | 377 | break; |
gertk | 0:806c2f2a7d47 | 378 | case 2: // Convert BCD to string. |
gertk | 0:806c2f2a7d47 | 379 | // On entry: |
gertk | 0:806c2f2a7d47 | 380 | // XY+1..7=BCD value |
gertk | 0:806c2f2a7d47 | 381 | // On exit: |
gertk | 0:806c2f2a7d47 | 382 | // XY+1..25=CR-terminated string |
gertk | 0:806c2f2a7d47 | 383 | break; |
gertk | 0:806c2f2a7d47 | 384 | } |
gertk | 0:806c2f2a7d47 | 385 | break; |
gertk | 0:806c2f2a7d47 | 386 | case 0x0f: // write TIME$ (not present in original BBC Basic) |
gertk | 0:806c2f2a7d47 | 387 | // On entry: |
gertk | 0:806c2f2a7d47 | 388 | // XY?0=function code |
gertk | 0:806c2f2a7d47 | 389 | // XY+1.. value to use. |
gertk | 0:806c2f2a7d47 | 390 | // Functions are: |
gertk | 0:806c2f2a7d47 | 391 | // 8 - Set time to value in format "HH:MM:SS" |
gertk | 0:806c2f2a7d47 | 392 | // 16 - Set date to value in format "Day,DD Mon Year" |
gertk | 0:806c2f2a7d47 | 393 | // 24 - Set time and date to value in format |
gertk | 0:806c2f2a7d47 | 394 | // "Day,DD Mon Year.HH:MM:SS" |
gertk | 0:806c2f2a7d47 | 395 | n=0; |
gertk | 0:806c2f2a7d47 | 396 | ad=hl; |
gertk | 0:806c2f2a7d47 | 397 | // printf(" write time$ function %d\n\r",rdmem(ad)); |
gertk | 0:806c2f2a7d47 | 398 | ad++; |
gertk | 0:806c2f2a7d47 | 399 | while (rdmem(ad)!=0x0d) buf[n++]=rdmem(ad++); // copy timestring to buffer |
gertk | 0:806c2f2a7d47 | 400 | buf[n]=0; |
gertk | 0:806c2f2a7d47 | 401 | // printf("trying to set time from %s\n\r",buf); |
gertk | 0:806c2f2a7d47 | 402 | break; |
gertk | 0:806c2f2a7d47 | 403 | } |
gertk | 0:806c2f2a7d47 | 404 | } |
gertk | 0:806c2f2a7d47 | 405 | |
gertk | 0:806c2f2a7d47 | 406 | // OSBYTE |
gertk | 0:806c2f2a7d47 | 407 | // on 6502 A register and X,Y are used for Low,High parameters |
gertk | 0:806c2f2a7d47 | 408 | // Z80 uses L and H (so X=L and H=Y <-> L=X and Y=H) |
gertk | 0:806c2f2a7d47 | 409 | void do_osbyte() { |
gertk | 0:806c2f2a7d47 | 410 | unsigned char temp; |
gertk | 0:806c2f2a7d47 | 411 | |
gertk | 0:806c2f2a7d47 | 412 | // printf("OSBYTE called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 413 | switch (a) { |
gertk | 0:806c2f2a7d47 | 414 | case 0x00: // NULL |
gertk | 0:806c2f2a7d47 | 415 | l=0xff; |
gertk | 0:806c2f2a7d47 | 416 | break; |
gertk | 0:806c2f2a7d47 | 417 | case 0x13: // ASCII 19 |
gertk | 0:806c2f2a7d47 | 418 | break; |
gertk | 0:806c2f2a7d47 | 419 | case 0x7c: // clear ESCAPE state |
gertk | 0:806c2f2a7d47 | 420 | wrmem(0xff80,rdmem(0xff80)&0x7f); |
gertk | 0:806c2f2a7d47 | 421 | break; |
gertk | 0:806c2f2a7d47 | 422 | case 0x7d: // set ESCAPE state |
gertk | 0:806c2f2a7d47 | 423 | wrmem(0xff80,rdmem(0xff80)|0x80); |
gertk | 0:806c2f2a7d47 | 424 | break; |
gertk | 0:806c2f2a7d47 | 425 | case 0x7e: // acknowledge ESCAPE state ? (CLOSE ALL!) |
gertk | 0:806c2f2a7d47 | 426 | wrmem(0xff80,rdmem(0xff80)&0x7f); |
gertk | 0:806c2f2a7d47 | 427 | break; |
gertk | 0:806c2f2a7d47 | 428 | case 0x7f: // read EOF on channel |
gertk | 0:806c2f2a7d47 | 429 | l=0x01; |
gertk | 0:806c2f2a7d47 | 430 | break; |
gertk | 0:806c2f2a7d47 | 431 | case 0x80: // read ADVAL(hl) |
gertk | 0:806c2f2a7d47 | 432 | h=0; |
gertk | 0:806c2f2a7d47 | 433 | l=0; |
gertk | 0:806c2f2a7d47 | 434 | break; |
gertk | 0:806c2f2a7d47 | 435 | case 0x81: // read key within time limit 'hl' centiseconds |
gertk | 0:806c2f2a7d47 | 436 | temp=hl; // get timeout value (100th seconds) |
gertk | 0:806c2f2a7d47 | 437 | do { |
gertk | 0:806c2f2a7d47 | 438 | l=getkey(); |
gertk | 0:806c2f2a7d47 | 439 | wait(0.01); |
gertk | 0:806c2f2a7d47 | 440 | } while ((temp--) && (!l)); |
gertk | 0:806c2f2a7d47 | 441 | |
gertk | 0:806c2f2a7d47 | 442 | if (l) { // we got a key |
gertk | 0:806c2f2a7d47 | 443 | if (l==0x1b) { // Escape ? |
gertk | 0:806c2f2a7d47 | 444 | f=(f&0xc4)|1|(a&0x28); // set carry |
gertk | 0:806c2f2a7d47 | 445 | h=0x1b; |
gertk | 0:806c2f2a7d47 | 446 | } else { |
gertk | 0:806c2f2a7d47 | 447 | anda(a); // clear carry |
gertk | 0:806c2f2a7d47 | 448 | h=0x00; // clear h |
gertk | 0:806c2f2a7d47 | 449 | } |
gertk | 0:806c2f2a7d47 | 450 | } else { // timeout |
gertk | 0:806c2f2a7d47 | 451 | f=(f&0xc4)|1|(a&0x28); // set carry |
gertk | 0:806c2f2a7d47 | 452 | h=0xff; // signal no key |
gertk | 0:806c2f2a7d47 | 453 | } |
gertk | 0:806c2f2a7d47 | 454 | break; // scan keyboard etc |
gertk | 0:806c2f2a7d47 | 455 | case 0x82: |
gertk | 0:806c2f2a7d47 | 456 | h=l=0; |
gertk | 0:806c2f2a7d47 | 457 | break; // Machine high order address |
gertk | 0:806c2f2a7d47 | 458 | case 0x83: |
gertk | 0:806c2f2a7d47 | 459 | h=PAGE>>8; |
gertk | 0:806c2f2a7d47 | 460 | l=(PAGE & 0xff); |
gertk | 0:806c2f2a7d47 | 461 | break; // lowest available memory address (PAGE) |
gertk | 0:806c2f2a7d47 | 462 | case 0x84: // highest available memory address (HIMEM) |
gertk | 0:806c2f2a7d47 | 463 | h=RAMEND>>8; |
gertk | 0:806c2f2a7d47 | 464 | l=RAMEND & 0xff; |
gertk | 0:806c2f2a7d47 | 465 | break; |
gertk | 0:806c2f2a7d47 | 466 | case 0x85: // read bottom of display RAM for a specific mode |
gertk | 0:806c2f2a7d47 | 467 | h=0x80; |
gertk | 0:806c2f2a7d47 | 468 | l=0x00; |
gertk | 0:806c2f2a7d47 | 469 | break; |
gertk | 0:806c2f2a7d47 | 470 | case 0x86: // return H=VPOS, L=POS |
gertk | 0:806c2f2a7d47 | 471 | h=cursor_ypos; |
gertk | 0:806c2f2a7d47 | 472 | l=cursor_xpos; |
gertk | 0:806c2f2a7d47 | 473 | break; |
gertk | 0:806c2f2a7d47 | 474 | case 0x87: // L=character on screen at cursor position |
gertk | 0:806c2f2a7d47 | 475 | h=7; |
gertk | 0:806c2f2a7d47 | 476 | l=0; |
gertk | 0:806c2f2a7d47 | 477 | break; |
gertk | 0:806c2f2a7d47 | 478 | case 0xda: // read/write the number of items in the VDU queue |
gertk | 0:806c2f2a7d47 | 479 | // on return H contains the new value, L the old |
gertk | 0:806c2f2a7d47 | 480 | temp=queue_bytes; |
gertk | 0:806c2f2a7d47 | 481 | queue_bytes=(queue_bytes & h)^l; |
gertk | 0:806c2f2a7d47 | 482 | h=queue_bytes; |
gertk | 0:806c2f2a7d47 | 483 | l=temp; |
gertk | 0:806c2f2a7d47 | 484 | break; // read/write the number of items in the VDU queue |
gertk | 0:806c2f2a7d47 | 485 | } |
gertk | 0:806c2f2a7d47 | 486 | // show_registers(); |
gertk | 0:806c2f2a7d47 | 487 | // wait(0.1); |
gertk | 0:806c2f2a7d47 | 488 | } |
gertk | 0:806c2f2a7d47 | 489 | |
gertk | 0:806c2f2a7d47 | 490 | void do_osreadchar() { |
gertk | 0:806c2f2a7d47 | 491 | a=getchar(); |
gertk | 0:806c2f2a7d47 | 492 | // test for ESCAPE |
gertk | 0:806c2f2a7d47 | 493 | if (a==27) { |
gertk | 0:806c2f2a7d47 | 494 | f=(f&0xc4)|1|(a&0x28); |
gertk | 0:806c2f2a7d47 | 495 | wrmem(0xff80,rdmem(0xff80)|0x80); |
gertk | 0:806c2f2a7d47 | 496 | } |
gertk | 0:806c2f2a7d47 | 497 | } |
gertk | 0:806c2f2a7d47 | 498 | |
gertk | 0:806c2f2a7d47 | 499 | void do_osnewline() { |
gertk | 0:806c2f2a7d47 | 500 | printchar(0x0a); |
gertk | 0:806c2f2a7d47 | 501 | printchar(0x0d); |
gertk | 0:806c2f2a7d47 | 502 | a=0x0d; |
gertk | 0:806c2f2a7d47 | 503 | } |
gertk | 0:806c2f2a7d47 | 504 | |
gertk | 0:806c2f2a7d47 | 505 | void do_osasci() { |
gertk | 0:806c2f2a7d47 | 506 | if (a==0x0d) do_osnewline(); |
gertk | 0:806c2f2a7d47 | 507 | else printchar(a); |
gertk | 0:806c2f2a7d47 | 508 | } |
gertk | 0:806c2f2a7d47 | 509 | |
gertk | 0:806c2f2a7d47 | 510 | void do_mainvdu() { |
gertk | 0:806c2f2a7d47 | 511 | printchar(a); |
gertk | 0:806c2f2a7d47 | 512 | } |
gertk | 0:806c2f2a7d47 | 513 | |
gertk | 0:806c2f2a7d47 | 514 | void do_gsinit() { |
gertk | 0:806c2f2a7d47 | 515 | printf("GSINIT called with PC=%04x A=%02x\n\r",pc,a); |
gertk | 0:806c2f2a7d47 | 516 | } |
gertk | 0:806c2f2a7d47 | 517 | |
gertk | 0:806c2f2a7d47 | 518 | void do_gsread() { |
gertk | 0:806c2f2a7d47 | 519 | } |
gertk | 0:806c2f2a7d47 | 520 | |
gertk | 0:806c2f2a7d47 | 521 | void do_osrdrm() { |
gertk | 0:806c2f2a7d47 | 522 | printf("OSRDRM called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 523 | } |
gertk | 0:806c2f2a7d47 | 524 | |
gertk | 0:806c2f2a7d47 | 525 | void do_oseven() { |
gertk | 0:806c2f2a7d47 | 526 | printf("OSEVEN called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 527 | } |
gertk | 0:806c2f2a7d47 | 528 | |
gertk | 0:806c2f2a7d47 | 529 | void do_oscli() { |
gertk | 0:806c2f2a7d47 | 530 | printf("OSCLI called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 531 | do { |
gertk | 0:806c2f2a7d47 | 532 | a=rdmem((h<<8)+l); |
gertk | 0:806c2f2a7d47 | 533 | if (!++l)h++; |
gertk | 0:806c2f2a7d47 | 534 | putchar(a); |
gertk | 0:806c2f2a7d47 | 535 | } while (a!=0x0d); |
gertk | 0:806c2f2a7d47 | 536 | } |
gertk | 0:806c2f2a7d47 | 537 | |
gertk | 0:806c2f2a7d47 | 538 | void do_osfile() { |
gertk | 0:806c2f2a7d47 | 539 | char buffer[200]; |
gertk | 0:806c2f2a7d47 | 540 | int n=0; |
gertk | 0:806c2f2a7d47 | 541 | FILE *fp; |
gertk | 0:806c2f2a7d47 | 542 | // get address of control block |
gertk | 0:806c2f2a7d47 | 543 | int controlblock=hl; |
gertk | 0:806c2f2a7d47 | 544 | int offset=rdmem(controlblock)+(rdmem(controlblock+1)<<8); |
gertk | 0:806c2f2a7d47 | 545 | // create a kludgy pointer from this offset to the filename |
gertk | 0:806c2f2a7d47 | 546 | char *filename=(char *)(ram+offset-RAMSTART); |
gertk | 0:806c2f2a7d47 | 547 | long load_address=rdmem(controlblock+2)+(rdmem(controlblock+3)<<8)+(rdmem(controlblock+4)<<16)+(rdmem(controlblock+5)<<24); |
gertk | 0:806c2f2a7d47 | 548 | long execution_address=rdmem(controlblock+6)+(rdmem(controlblock+7)<<8)+(rdmem(controlblock+8)<<16)+(rdmem(controlblock+9)<<24); |
gertk | 0:806c2f2a7d47 | 549 | long start_or_length=rdmem(controlblock+10)+(rdmem(controlblock+11)<<8)+(rdmem(controlblock+12)<<16)+(rdmem(controlblock+13)<<24); |
gertk | 0:806c2f2a7d47 | 550 | long end_address_or_attributes=rdmem(controlblock+14)+(rdmem(controlblock+15)<<8)+(rdmem(controlblock+16)<<16)+(rdmem(controlblock+17)<<24); |
gertk | 0:806c2f2a7d47 | 551 | |
gertk | 0:806c2f2a7d47 | 552 | |
gertk | 0:806c2f2a7d47 | 553 | // printf("OSFILE called with PC=%04x A=%02x H=%02x L=%02x\n\r",pc,a,h,l); |
gertk | 0:806c2f2a7d47 | 554 | |
gertk | 0:806c2f2a7d47 | 555 | // for (n=0; n<=0x11; n++) printf("offset %02x value %02x\n\r",n,rdmem(controlblock+n)); |
gertk | 0:806c2f2a7d47 | 556 | |
gertk | 0:806c2f2a7d47 | 557 | n=0; |
gertk | 0:806c2f2a7d47 | 558 | while (filename[n]!=0x0d) n++; |
gertk | 0:806c2f2a7d47 | 559 | // overwrite 0x0d with end of string |
gertk | 0:806c2f2a7d47 | 560 | filename[n]=0x00; |
gertk | 0:806c2f2a7d47 | 561 | |
gertk | 0:806c2f2a7d47 | 562 | // now determine what to do |
gertk | 0:806c2f2a7d47 | 563 | switch (a) { |
gertk | 0:806c2f2a7d47 | 564 | case 0x00: // save a section of memory as a named file |
gertk | 0:806c2f2a7d47 | 565 | sprintf(buffer,"/local/%s",filename); |
gertk | 0:806c2f2a7d47 | 566 | // printf("Saving file %s load adr:%08lx exec adr:%08lx start/length%08lx end/attr:%08lx\n\r",filename,load_address,execution_address,start_or_length,end_address_or_attributes); |
gertk | 0:806c2f2a7d47 | 567 | fp=fopen(buffer, "w"); |
gertk | 0:806c2f2a7d47 | 568 | if (fp) { |
gertk | 0:806c2f2a7d47 | 569 | n=start_or_length; |
gertk | 0:806c2f2a7d47 | 570 | while (n!=end_address_or_attributes) fputc(rdmem(n++),fp); |
gertk | 0:806c2f2a7d47 | 571 | fclose(fp); |
gertk | 0:806c2f2a7d47 | 572 | a=1; |
gertk | 0:806c2f2a7d47 | 573 | } else { |
gertk | 0:806c2f2a7d47 | 574 | // printf("could not write %s\n\r",buffer); |
gertk | 0:806c2f2a7d47 | 575 | a=0; |
gertk | 0:806c2f2a7d47 | 576 | pc=rdmem(0xfffa)+(rdmem(0xfffb)<<8); // do BRK |
gertk | 0:806c2f2a7d47 | 577 | } |
gertk | 0:806c2f2a7d47 | 578 | break; |
gertk | 0:806c2f2a7d47 | 579 | case 0x01: // write the catalogue information (only) for the named file (disc only) |
gertk | 0:806c2f2a7d47 | 580 | break; |
gertk | 0:806c2f2a7d47 | 581 | case 0x02: // write the load address (only) for the named file (disc only) |
gertk | 0:806c2f2a7d47 | 582 | break; |
gertk | 0:806c2f2a7d47 | 583 | case 0x03: // write the execution address (only) for the named file (disc only) |
gertk | 0:806c2f2a7d47 | 584 | break; |
gertk | 0:806c2f2a7d47 | 585 | case 0x04: // write the attributes (only) for the named file (disc only) |
gertk | 0:806c2f2a7d47 | 586 | break; |
gertk | 0:806c2f2a7d47 | 587 | case 0x05: // read the named file's catalogue information, place file type in A (disc only) |
gertk | 0:806c2f2a7d47 | 588 | break; |
gertk | 0:806c2f2a7d47 | 589 | case 0x06: // delete the named file (disc only) |
gertk | 0:806c2f2a7d47 | 590 | break; |
gertk | 0:806c2f2a7d47 | 591 | case 0xff: // load the named file and read the named file's catalogue information |
gertk | 0:806c2f2a7d47 | 592 | sprintf(buffer,"/local/%s",filename); |
gertk | 0:806c2f2a7d47 | 593 | // printf("Loading file %s load adr:%08lx exec adr:%08lx start/length%08lx end/attr:%08lx\n\r",buffer,load_address,execution_address,start_or_length,end_address_or_attributes); |
gertk | 0:806c2f2a7d47 | 594 | fp = fopen(buffer, "r"); |
gertk | 0:806c2f2a7d47 | 595 | if (fp) { |
gertk | 0:806c2f2a7d47 | 596 | n=load_address; |
gertk | 0:806c2f2a7d47 | 597 | while (!feof(fp)) wrmem(n++,fgetc(fp)); |
gertk | 0:806c2f2a7d47 | 598 | fclose(fp); |
gertk | 0:806c2f2a7d47 | 599 | a=1; // file found |
gertk | 0:806c2f2a7d47 | 600 | } else { |
gertk | 0:806c2f2a7d47 | 601 | // printf("Could not open %s\n",buffer); |
gertk | 0:806c2f2a7d47 | 602 | a=0; |
gertk | 0:806c2f2a7d47 | 603 | pc=rdmem(0xfffa)+(rdmem(0xfffb)<<8); // do BRK |
gertk | 0:806c2f2a7d47 | 604 | } |
gertk | 0:806c2f2a7d47 | 605 | break; |
gertk | 0:806c2f2a7d47 | 606 | } |
gertk | 0:806c2f2a7d47 | 607 | } |
gertk | 0:806c2f2a7d47 | 608 | |
gertk | 0:806c2f2a7d47 | 609 | void terminalgets(char *buffer) { |
gertk | 0:806c2f2a7d47 | 610 | int n=0; |
gertk | 0:806c2f2a7d47 | 611 | int key=0; |
gertk | 0:806c2f2a7d47 | 612 | do { |
gertk | 0:806c2f2a7d47 | 613 | key=getchar(); |
gertk | 0:806c2f2a7d47 | 614 | buffer[n]=key; |
gertk | 0:806c2f2a7d47 | 615 | putchar(key); |
gertk | 0:806c2f2a7d47 | 616 | if (n<16) n++; |
gertk | 0:806c2f2a7d47 | 617 | } while (key != 0x0d); |
gertk | 0:806c2f2a7d47 | 618 | buffer[n]=0; |
gertk | 0:806c2f2a7d47 | 619 | } |
gertk | 0:806c2f2a7d47 | 620 | |
gertk | 0:806c2f2a7d47 | 621 | |
gertk | 0:806c2f2a7d47 | 622 | // here the OS calls are recognized and |
gertk | 0:806c2f2a7d47 | 623 | // diverted to the mbed routines. |
gertk | 0:806c2f2a7d47 | 624 | // this needs to be replaced by native Z80 code |
gertk | 0:806c2f2a7d47 | 625 | void do_mos() { |
gertk | 0:806c2f2a7d47 | 626 | // printf("Entering MOS emulation with PC %04x\n\r",pc); |
gertk | 0:806c2f2a7d47 | 627 | |
gertk | 0:806c2f2a7d47 | 628 | // compensate pc for length of ED55 opcode |
gertk | 0:806c2f2a7d47 | 629 | switch (pc-2) { |
gertk | 0:806c2f2a7d47 | 630 | case OSBYTE: |
gertk | 0:806c2f2a7d47 | 631 | do_osbyte(); |
gertk | 0:806c2f2a7d47 | 632 | break; |
gertk | 0:806c2f2a7d47 | 633 | case OSWORD: |
gertk | 0:806c2f2a7d47 | 634 | do_osword(); |
gertk | 0:806c2f2a7d47 | 635 | break; |
gertk | 0:806c2f2a7d47 | 636 | case OSWRCH: |
gertk | 0:806c2f2a7d47 | 637 | printchar(a); |
gertk | 0:806c2f2a7d47 | 638 | break; |
gertk | 0:806c2f2a7d47 | 639 | case OSRDCH: |
gertk | 0:806c2f2a7d47 | 640 | do_osreadchar(); |
gertk | 0:806c2f2a7d47 | 641 | break; |
gertk | 0:806c2f2a7d47 | 642 | case OSNEWL: |
gertk | 0:806c2f2a7d47 | 643 | do_osnewline(); |
gertk | 0:806c2f2a7d47 | 644 | break; |
gertk | 0:806c2f2a7d47 | 645 | case OSASCI: |
gertk | 0:806c2f2a7d47 | 646 | do_osasci(); |
gertk | 0:806c2f2a7d47 | 647 | break; |
gertk | 0:806c2f2a7d47 | 648 | case MAINVDU: |
gertk | 0:806c2f2a7d47 | 649 | do_mainvdu(); |
gertk | 0:806c2f2a7d47 | 650 | break; |
gertk | 0:806c2f2a7d47 | 651 | case GSINIT: |
gertk | 0:806c2f2a7d47 | 652 | do_gsinit(); |
gertk | 0:806c2f2a7d47 | 653 | break; |
gertk | 0:806c2f2a7d47 | 654 | case GSREAD: |
gertk | 0:806c2f2a7d47 | 655 | do_gsread(); |
gertk | 0:806c2f2a7d47 | 656 | break; |
gertk | 0:806c2f2a7d47 | 657 | case OSRDRM: |
gertk | 0:806c2f2a7d47 | 658 | do_osrdrm(); |
gertk | 0:806c2f2a7d47 | 659 | break; |
gertk | 0:806c2f2a7d47 | 660 | case OSEVEN: |
gertk | 0:806c2f2a7d47 | 661 | do_oseven(); |
gertk | 0:806c2f2a7d47 | 662 | break; |
gertk | 0:806c2f2a7d47 | 663 | case OSCLI: |
gertk | 0:806c2f2a7d47 | 664 | do_oscli(); |
gertk | 0:806c2f2a7d47 | 665 | break; |
gertk | 0:806c2f2a7d47 | 666 | case OSFILE: |
gertk | 0:806c2f2a7d47 | 667 | do_osfile(); |
gertk | 0:806c2f2a7d47 | 668 | break; |
gertk | 0:806c2f2a7d47 | 669 | } |
gertk | 0:806c2f2a7d47 | 670 | } |
gertk | 0:806c2f2a7d47 | 671 | |
gertk | 0:806c2f2a7d47 | 672 | void listdir(void) { |
gertk | 0:806c2f2a7d47 | 673 | DIR *d; |
gertk | 0:806c2f2a7d47 | 674 | struct dirent *p; |
gertk | 0:806c2f2a7d47 | 675 | |
gertk | 0:806c2f2a7d47 | 676 | d = opendir("/sd"); |
gertk | 0:806c2f2a7d47 | 677 | if (d != NULL) { |
gertk | 0:806c2f2a7d47 | 678 | while ((p = readdir(d)) != NULL) { |
gertk | 0:806c2f2a7d47 | 679 | printf(" - %s\r\n", p->d_name); |
gertk | 0:806c2f2a7d47 | 680 | } |
gertk | 0:806c2f2a7d47 | 681 | } else { |
gertk | 0:806c2f2a7d47 | 682 | printf("Could not open directory!\n"); |
gertk | 0:806c2f2a7d47 | 683 | } |
gertk | 0:806c2f2a7d47 | 684 | closedir(d); |
gertk | 0:806c2f2a7d47 | 685 | } |
gertk | 0:806c2f2a7d47 | 686 | |
gertk | 0:806c2f2a7d47 | 687 | |
gertk | 0:806c2f2a7d47 | 688 | |
gertk | 0:806c2f2a7d47 | 689 | |
gertk | 0:806c2f2a7d47 | 690 | |
gertk | 0:806c2f2a7d47 | 691 | // ================================================================ |
gertk | 0:806c2f2a7d47 | 692 | // main loop |
gertk | 0:806c2f2a7d47 | 693 | // ================================================================ |
gertk | 0:806c2f2a7d47 | 694 | int main() { |
gertk | 0:806c2f2a7d47 | 695 | |
gertk | 0:806c2f2a7d47 | 696 | // serial port on at 115200 baud |
gertk | 0:806c2f2a7d47 | 697 | linktopc.baud(115200); |
gertk | 0:806c2f2a7d47 | 698 | setbuf(stdout, NULL); // no buffering for this filehandle |
gertk | 0:806c2f2a7d47 | 699 | |
gertk | 0:806c2f2a7d47 | 700 | // reset all Z80 registers to some initial values |
gertk | 0:806c2f2a7d47 | 701 | a=f=b=c=d=e=h=l=a1=f1=b1=c1=d1=e1=h1=l1=i=iff1=iff2=im=r=0; |
gertk | 0:806c2f2a7d47 | 702 | ixoriy=new_ixoriy=0; |
gertk | 0:806c2f2a7d47 | 703 | ix=iy=sp=pc=0; |
gertk | 0:806c2f2a7d47 | 704 | |
gertk | 0:806c2f2a7d47 | 705 | queue_bytes=0; |
gertk | 0:806c2f2a7d47 | 706 | |
gertk | 0:806c2f2a7d47 | 707 | // init MOS vectors |
gertk | 0:806c2f2a7d47 | 708 | init_ramtop(); |
gertk | 0:806c2f2a7d47 | 709 | |
gertk | 0:806c2f2a7d47 | 710 | init_screen(); |
gertk | 0:806c2f2a7d47 | 711 | home_cursor(); |
gertk | 0:806c2f2a7d47 | 712 | |
gertk | 0:806c2f2a7d47 | 713 | // endless loop |
gertk | 0:806c2f2a7d47 | 714 | while (1) { |
gertk | 0:806c2f2a7d47 | 715 | // wait(0.01); |
gertk | 0:806c2f2a7d47 | 716 | r++; |
gertk | 0:806c2f2a7d47 | 717 | // this is some optimization for the IX and IY opcodes (DD/FD) |
gertk | 0:806c2f2a7d47 | 718 | ixoriy=new_ixoriy; |
gertk | 0:806c2f2a7d47 | 719 | new_ixoriy=0; |
gertk | 0:806c2f2a7d47 | 720 | |
gertk | 0:806c2f2a7d47 | 721 | // fetch opcode and execute, the include does all the heavy decoding |
gertk | 0:806c2f2a7d47 | 722 | switch (fetch(pc++)) { |
gertk | 0:806c2f2a7d47 | 723 | #include "z80ops.h" |
gertk | 0:806c2f2a7d47 | 724 | } |
gertk | 0:806c2f2a7d47 | 725 | |
gertk | 0:806c2f2a7d47 | 726 | // next is the interrupt emulator (only IM1 mode) |
gertk | 0:806c2f2a7d47 | 727 | // interrupt pending? if new_ixoriy is set or iff1==0 don't do interrupt yet (continue DD/FD opcode) |
gertk | 0:806c2f2a7d47 | 728 | // if (intpend && !new_ixoriy && iff1) { |
gertk | 0:806c2f2a7d47 | 729 | // are we HALT-ed ? then resume |
gertk | 0:806c2f2a7d47 | 730 | // if (fetch(pc)==0x76) pc++; |
gertk | 0:806c2f2a7d47 | 731 | |
gertk | 0:806c2f2a7d47 | 732 | // block further interrupts for now |
gertk | 0:806c2f2a7d47 | 733 | // iff1=0; |
gertk | 0:806c2f2a7d47 | 734 | |
gertk | 0:806c2f2a7d47 | 735 | // do the call to 00x38 |
gertk | 0:806c2f2a7d47 | 736 | // push2(pc); // save old pc |
gertk | 0:806c2f2a7d47 | 737 | // pc=0x0038; // setup new pc |
gertk | 0:806c2f2a7d47 | 738 | // intpend=0; // release interrupt pending flag; |
gertk | 0:806c2f2a7d47 | 739 | // } // if intpend |
gertk | 0:806c2f2a7d47 | 740 | } // while |
gertk | 0:806c2f2a7d47 | 741 | } |