| /* swtp_sys.c: SWTP 6800 system interface | |
| Copyright (c) 2005, William Beech | |
| Permission is hereby granted, free of charge, to any person obtaining a | |
| copy of this software and associated documentation files (the "Software"), | |
| to deal in the Software without restriction, including without limitation | |
| the rights to use, copy, modify, merge, publish, distribute, sublicense, | |
| and/or sell copies of the Software, and to permit persons to whom the | |
| Software is furnished to do so, subject to the following conditions: | |
| The above copyright notice and this permission notice shall be included in | |
| all copies or substantial portions of the Software. | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL | |
| WILLIAM A BEECH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER | |
| IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. | |
| Except as contained in this notice, the name of William A. Beech shall not | |
| be used in advertising or otherwise to promote the sale, use or other dealings | |
| in this Software without prior written authorization from William A. Beech. | |
| Based on work by Charles E Owen (c) 1997 and Peter Schorn (c) 2002-2005 | |
| */ | |
| #include <ctype.h> | |
| #include <string.h> | |
| #include "swtp_defs.h" | |
| /* externals */ | |
| extern DEVICE cpu_dev; | |
| extern DEVICE dsk_dev; | |
| extern UNIT cpu_unit; | |
| extern REG cpu_reg[]; | |
| extern DEVICE sio_dev; | |
| extern DEVICE ptr_dev; | |
| extern DEVICE ptp_dev; | |
| extern DEVICE lpt_dev; | |
| extern unsigned char M[]; | |
| extern int32 saved_PC; | |
| extern int32 sim_switches; | |
| //extern int32 (*sim_vm_fprint_addr)(FILE*, DEVICE*,t_addr); | |
| /* prototypes */ | |
| int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag); | |
| int32 fprint_sym (FILE *of, int32 addr, uint32 *val, | |
| UNIT *uptr, int32 sw); | |
| t_addr fprint_addr(FILE *stream, DEVICE *dptr, t_addr addr); | |
| int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw); | |
| void sim_special_init (void); | |
| /* links into scp */ | |
| void (*sim_vm_init)(void) = &sim_special_init; | |
| /* SCP data structures | |
| sim_name simulator name string | |
| sim_PC pointer to saved PC register descriptor | |
| sim_emax number of words needed for examine | |
| sim_devices array of pointers to simulated devices | |
| sim_stop_messages array of pointers to stop messages | |
| sim_load binary loader | |
| */ | |
| char sim_name[] = "SWTP 6800"; | |
| REG *sim_PC = &cpu_reg[0]; | |
| int32 sim_emax = 16; | |
| DEVICE *sim_devices[] = { &cpu_dev, &sio_dev, &ptp_dev, &ptr_dev, &dsk_dev, NULL }; | |
| const char *sim_stop_messages[] = { | |
| "Unknown error", | |
| "Unknown I/O Instruction", | |
| "HALT instruction", | |
| "Breakpoint", | |
| "Invalid Opcode", | |
| "Invalid Memory" }; | |
| static const char *opcode[] = { | |
| "???", "NOP", "???", "???", //0x00 | |
| "???", "???", "TAP", "TPA", | |
| "INX", "DEX", "CLV", "SEV", | |
| "CLC", "SEC", "CLI", "SEI", | |
| "SBA", "CBA", "???", "???", //0x10 | |
| "???", "???", "TAB", "TBA", | |
| "???", "DAA", "???", "ABA", | |
| "???", "???", "???", "???", | |
| "BRA", "???", "BHI", "BLS", //0x20 | |
| "BCC", "BCS", "BNE", "BEQ", | |
| "BVC", "BVS", "BPL", "BMI", | |
| "BGE", "BLT", "BGT", "BLE", | |
| "TSX", "INS", "PULA", "PULB", //0x30 | |
| "DES", "TXS", "PSHA", "PSHB", | |
| "???", "RTS", "???", "RTI", | |
| "???", "???", "WAI", "SWI", | |
| "NEGA", "???", "???", "COMA", //0x40 | |
| "LSRA", "???", "RORA", "ASRA", | |
| "ASLA", "ROLA", "DECA", "???", | |
| "INCA", "TSTA", "???", "CLRA", | |
| "NEGB", "???", "???", "COMB", //0x50 | |
| "LSRB", "???", "RORB", "ASRB", | |
| "ASLB", "ROLB", "DECB", "???", | |
| "INCB", "TSTB", "???", "CLRB", | |
| "NEG", "???", "???", "COM", //0x60 | |
| "LSR", "???", "ROR", "ASR", | |
| "ASL", "ROL", "DEC", "???", | |
| "INC", "TST", "JMP", "CLR", | |
| "NEG", "???", "???", "COM", //0x70 | |
| "LSR", "???", "ROR", "ASR", | |
| "ASL", "ROL", "DEC", "???", | |
| "INC", "TST", "JMP", "CLR", | |
| "SUBA", "CMPA", "SBCA", "???", //0x80 | |
| "ANDA", "BITA", "LDAA", "???", | |
| "EORA", "ADCA", "ORAA", "ADDA", | |
| "CPX", "BSR", "LDS", "???", | |
| "SUBA", "CMPA", "SBCA", "???", //0x90 | |
| "ANDA", "BITA", "LDAA", "STAA", | |
| "EORA", "ADCA", "ORAA", "ADDA", | |
| "CPX", "???", "LDS", "STS", | |
| "SUBA", "CMPA", "SBCA", "???", //0xA0 | |
| "ANDA", "BITA", "LDAA", "STAA", | |
| "EORA", "ADCA", "ORAA", "ADDA", | |
| "CPX X", "JSR X", "LDS X", "STS X", | |
| "SUBA", "CMPA", "SBCA", "???", //0xB0 | |
| "ANDA", "BITA", "LDAA", "STAA", | |
| "EORA", "ADCA", "ORAA", "ADDA", | |
| "CPX", "JSR", "LDS", "STS", | |
| "SUBB", "CMPB", "SBCB", "???", //0xC0 | |
| "ANDB", "BITB", "LDAB", "???", | |
| "EORB", "ADCB", "ORAB", "ADDB", | |
| "???", "???", "LDX", "???", | |
| "SUBB", "CMPB", "SBCB", "???", //0xD0 | |
| "ANDB", "BITB", "LDAB", "STAB", | |
| "EORB", "ADCB", "ORAB", "ADDB", | |
| "???", "???", "LDX", "STX", | |
| "SUBB", "CMPB", "SBCB", "???", //0xE0 | |
| "ANDB", "BITB", "LDAB", "STAB", | |
| "EORB", "ADCB", "ORAB", "ADDB", | |
| "???", "???", "LDX", "STX", | |
| "SUBB", "CMPB", "SBCB", "???", //0xF0 | |
| "ANDB", "BITB", "LDAB", "STAB", | |
| "EORB", "ADCB", "ORAB", "ADDB", | |
| "???", "???", "LDX", "STX", | |
| }; | |
| int32 oplen[256] = { | |
| 0,1,0,0,0,0,1,1,1,1,1,1,1,1,1,1, //0x00 | |
| 1,1,0,0,0,0,1,1,0,1,0,1,0,0,0,0, | |
| 2,0,2,2,2,2,2,2,2,2,2,2,2,2,2,2, | |
| 1,1,1,1,1,1,1,1,0,1,0,1,0,0,1,1, | |
| 1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, //0x40 | |
| 1,0,0,1,1,0,1,1,1,1,1,0,1,1,0,1, | |
| 2,0,0,2,2,0,2,2,2,2,2,0,2,2,2,2, | |
| 3,0,0,3,3,0,3,3,3,3,3,0,3,3,3,3, | |
| 2,2,2,0,2,2,2,0,2,2,2,2,3,2,3,0, //0x80 | |
| 2,2,2,0,2,2,2,2,2,2,2,2,2,0,2,2, | |
| 2,2,2,0,2,2,2,2,2,2,2,2,2,2,2,2, | |
| 3,3,3,0,3,3,3,3,3,3,3,3,3,3,3,3, | |
| 2,2,2,0,2,2,2,0,2,2,2,2,0,0,3,0, //0xC0 | |
| 2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, | |
| 2,2,2,0,2,2,2,2,2,2,2,2,0,0,2,2, | |
| 3,3,3,0,3,3,3,3,3,3,3,3,0,0,3,3 }; | |
| /* This is the dumper/loader. This command uses the -h to signify a | |
| hex dump/load vice a binary one. If no address is given to load, it | |
| takes the address from the hex record or the current PC for binary. | |
| */ | |
| int32 sim_load (FILE *fileref, char *cptr, char *fnam, int flag) | |
| { | |
| int32 i, cnt = 0, addr = 0, start = 0x10000, end = 0, bytecnt, | |
| cksum1, cksum, bytes[250]; | |
| char buffer[256]; | |
| sscanf(cptr," %x-%x", &start, &end); | |
| if (flag) { // dump | |
| if (start == 0x10000) // no address parameter | |
| return SCPE_2FARG; | |
| if (sim_switches & 0x80) { // hex dump | |
| addr = start; | |
| while (addr <= end) { // more records to write | |
| if ((addr + 16) <= end) // how many bytes this record | |
| bytecnt = 16 + 3; | |
| else | |
| bytecnt = end - addr + 4; | |
| cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum | |
| fprintf(fileref, "S1%02X%02X%02X", bytecnt, addr>>8, addr&0xFF); //header | |
| for (i=0; i<bytecnt-3; i++, addr++, cnt++) { // data | |
| fprintf(fileref, "%02X", M[addr]); | |
| cksum -= M[addr]; | |
| } | |
| fprintf(fileref, "%02X\r\n", cksum & 0xff); // eor | |
| } | |
| fprintf(fileref, "S9\r\n"); // eof | |
| } else { // binary dump | |
| for (addr = start; addr <= end; addr++, cnt++) { | |
| putc(M[addr], fileref); | |
| } | |
| } | |
| printf ("%d Bytes dumped starting at %04X\n", cnt, start); | |
| } else { // load | |
| if (sim_switches & 0x80) { // hex load | |
| while ((fgets(buffer, 255, fileref)) != NULL) { | |
| if (buffer[0] != 'S') | |
| printf("Not a Motorola hex format file\n"); | |
| else { | |
| if (buffer[0] == '0') // name record | |
| printf("Name record found and ignored\n"); | |
| else if (buffer[1] == '1') { // another record | |
| sscanf(buffer+2,"%2x%4x", &bytecnt, &addr); | |
| if (start == 0x10000) | |
| start = addr; | |
| for (i=0; i < bytecnt-3; i++) | |
| sscanf(buffer+8+(2*i), "%2x", &bytes[i]); | |
| sscanf(buffer+8+(2*i), "%2x", &cksum1); | |
| cksum = -1 - (bytecnt) - (addr >> 8) - (addr & 0xFF); //init cksum | |
| for (i=0; i < bytecnt-3; i++) | |
| cksum -= bytes[i]; | |
| cksum &= 0xFF; | |
| if (cksum != cksum1) | |
| printf("Checksum error\n"); | |
| else { | |
| for (i=0; i < bytecnt-3; i++) { | |
| M[addr++] = bytes[i]; | |
| cnt++; | |
| } | |
| } | |
| } else if (buffer[1] == '9') // end of file | |
| printf("End of file\n"); | |
| } | |
| } | |
| } else { // binary load | |
| if (start == 0x10000) // no starting address | |
| addr = saved_PC; | |
| else | |
| addr = start; | |
| start = addr; | |
| while ((i = getc (fileref)) != EOF) { | |
| M[addr] = i; | |
| addr++; | |
| cnt++; | |
| } | |
| } | |
| printf ("%d Bytes loaded starting at %04X\n", cnt, start); | |
| } | |
| return (SCPE_OK); | |
| } | |
| /* Symbolic output | |
| Inputs: | |
| *of = output stream | |
| addr = current PC | |
| *val = pointer to values | |
| *uptr = pointer to unit | |
| sw = switches | |
| Outputs: | |
| status = error code | |
| */ | |
| int32 fprint_sym (FILE *of, int32 addr, uint32 *val, | |
| UNIT *uptr, int32 sw) | |
| { | |
| int32 i, inst, inst1; | |
| if (sw & SWMASK ('D')) { // dump memory | |
| for (i=0; i<16; i++) | |
| fprintf(of, "%02X ", val[i]); | |
| fprintf(of, " "); | |
| for (i=0; i<16; i++) | |
| if (isprint(val[i])) | |
| fprintf(of, "%c", val[i]); | |
| else | |
| fprintf(of, "."); | |
| return -15; | |
| } else if (sw & SWMASK ('M')) { // dump instruction mnemonic | |
| inst = val[0]; | |
| if (!oplen[inst]) { // invalid opcode | |
| fprintf(of, "%02X", inst); | |
| return 0; | |
| } | |
| inst1 = inst & 0xF0; | |
| fprintf (of, "%s", opcode[inst]); // mnemonic | |
| if (strlen(opcode[inst]) == 3) | |
| fprintf(of, " "); | |
| if (inst1 == 0x20 || inst == 0x8D) { // rel operand | |
| inst1 = val[1]; | |
| if (val[1] & 0x80) | |
| inst1 |= 0xFF00; | |
| fprintf(of, " $%04X", (addr + inst1 + 2) & ADDRMASK); | |
| } else if (inst1 == 0x80 || inst1 == 0xC0) { // imm operand | |
| if ((inst & 0x0F) < 0x0C) | |
| fprintf(of, " #$%02X", val[1]); | |
| else | |
| fprintf(of, " #$%02X%02X", val[1], val[2]); | |
| } else if (inst1 == 0x60 || inst1 == 0xA0 || inst1 == 0xE0) // ind operand | |
| fprintf(of, " %d,X", val[1]); | |
| else if (inst1 == 0x70 || inst1 == 0xb0 || inst1 == 0xF0) // ext operand | |
| fprintf(of, " $%02X%02X", val[1], val[2]); | |
| return (-(oplen[inst] - 1)); | |
| } else | |
| return SCPE_ARG; | |
| } | |
| /* address output routine */ | |
| t_addr fprint_addr(FILE *of, DEVICE *dptr, t_addr addr) | |
| { | |
| fprintf(of, "%04X", addr); | |
| return 0; | |
| } | |
| /* Symbolic input | |
| Inputs: | |
| *cptr = pointer to input string | |
| addr = current PC | |
| *uptr = pointer to unit | |
| *val = pointer to output values | |
| sw = switches | |
| Outputs: | |
| status = error status | |
| */ | |
| int32 parse_sym (char *cptr, int32 addr, UNIT *uptr, uint32 *val, int32 sw) | |
| { | |
| int32 cflag, i = 0, j, r; | |
| char gbuf[CBUFSIZE]; | |
| cflag = (uptr == NULL) || (uptr == &cpu_unit); | |
| while (isspace (*cptr)) cptr++; /* absorb spaces */ | |
| if ((sw & SWMASK ('A')) || ((*cptr == '\'') && cptr++)) { /* ASCII char? */ | |
| if (cptr[0] == 0) | |
| return SCPE_ARG; /* must have 1 char */ | |
| val[0] = (uint32) cptr[0]; | |
| return SCPE_OK; | |
| } | |
| if ((sw & SWMASK ('C')) || ((*cptr == '"') && cptr++)) { /* ASCII string? */ | |
| if (cptr[0] == 0) | |
| return SCPE_ARG; /* must have 1 char */ | |
| val[0] = ((uint32) cptr[0] << 8) + (uint32) cptr[1]; | |
| return SCPE_OK; | |
| } | |
| /* An instruction: get opcode (all characters until null, comma, | |
| or numeric (including spaces). | |
| */ | |
| while (1) { | |
| if (*cptr == ',' || *cptr == '\0' || | |
| isdigit(*cptr)) | |
| break; | |
| gbuf[i] = toupper(*cptr); | |
| cptr++; | |
| i++; | |
| } | |
| /* Allow for RST which has numeric as part of opcode */ | |
| if (toupper(gbuf[0]) == 'R' && | |
| toupper(gbuf[1]) == 'S' && | |
| toupper(gbuf[2]) == 'T') { | |
| gbuf[i] = toupper(*cptr); | |
| cptr++; | |
| i++; | |
| } | |
| /* Allow for 'MOV' which is only opcode that has comma in it. */ | |
| if (toupper(gbuf[0]) == 'M' && | |
| toupper(gbuf[1]) == 'O' && | |
| toupper(gbuf[2]) == 'V') { | |
| gbuf[i] = toupper(*cptr); | |
| cptr++; | |
| i++; | |
| gbuf[i] = toupper(*cptr); | |
| cptr++; | |
| i++; | |
| } | |
| /* kill trailing spaces if any */ | |
| gbuf[i] = '\0'; | |
| for (j = i - 1; gbuf[j] == ' '; j--) { | |
| gbuf[j] = '\0'; | |
| } | |
| /* find opcode in table */ | |
| for (j = 0; j < 256; j++) { | |
| if (strcmp(gbuf, opcode[j]) == 0) | |
| break; | |
| } | |
| if (j > 255) /* not found */ | |
| return SCPE_ARG; | |
| val[0] = j; /* store opcode */ | |
| if (oplen[j] < 2) /* if 1-byter we are done */ | |
| return SCPE_OK; | |
| if (*cptr == ',') cptr++; | |
| cptr = get_glyph(cptr, gbuf, 0); /* get address */ | |
| sscanf(gbuf, "%o", &r); | |
| if (oplen[j] == 2) { | |
| val[1] = r & 0xFF; | |
| return (-1); | |
| } | |
| val[1] = r & 0xFF; | |
| val[2] = (r >> 8) & 0xFF; | |
| return (-2); | |
| } | |
| /* initialize optional interfaces */ | |
| void sim_special_init (void) | |
| { | |
| // *sim_vm_fprint_addr = &fprint_addr; | |
| } | |