From: Alan Cox Date: Fri, 13 Jul 2018 00:24:53 +0000 (+0100) Subject: cpuinfo: first cut at a cpuinfo command X-Git-Url: https://git.ndcode.org/public/gitweb.cgi?a=commitdiff_plain;h=cf9c47b1b39ef949b74391065b5451ea4699fc4e;p=FUZIX.git cpuinfo: first cut at a cpuinfo command This one only does Z80 and needs some deubgging and testing before it's at all reliable. 6502 NMOS/CMOS 65C816 and 6809/6309 are left as an exercise to the reader 8) --- diff --git a/Applications/util/Makefile.z80 b/Applications/util/Makefile.z80 index 24d484ca..bf4036b0 100644 --- a/Applications/util/Makefile.z80 +++ b/Applications/util/Makefile.z80 @@ -33,6 +33,7 @@ SRCSNS = \ reboot.c \ rm.c \ rmdir.c \ + substroot.c \ sum.c \ sync.c \ tee.c \ @@ -49,6 +50,7 @@ SRCS = banner.c \ bogomips.c \ cal.c \ cksum.c \ + cpuinfo.c \ cut.c \ dd.c \ decomp16.c \ diff --git a/Applications/util/cpuinfo.1 b/Applications/util/cpuinfo.1 new file mode 100644 index 00000000..096f78ad --- /dev/null +++ b/Applications/util/cpuinfo.1 @@ -0,0 +1,19 @@ +CPUINFO(1) +## NAME +*cpuinfo* - display information about the processor(s) in use +## SYNOPSIS +*cpuinfo* \[-p port\] +## DESCRIPTION +The *cpuinfo* command displays available information about the processor. +The information displayed and the detail level is dependant upon the +processor itself, and what identication facilities are available. + +For some processors such as the Z80 it is necessary to provide a suitable +I/O port for parts of the identification. For a Z80 system this should be a +port which can be written and reads back the same value while not having any +immediate side effect. The command will restore the port state. + +## STANDARDS +cpuinfo is a Fuzix specific command +## AUTHOR +Written by Alan Cox diff --git a/Applications/util/cpuinfo.c b/Applications/util/cpuinfo.c new file mode 100644 index 00000000..af5fbe7c --- /dev/null +++ b/Applications/util/cpuinfo.c @@ -0,0 +1,253 @@ +/* + * (C) Copyright 2018 Alan Cox + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include +#include +#include + +unsigned int port; +uint8_t port_opt; + +#if defined(__SDCC_z80) || defined(__SDCC_z180) + +#define CPU_Z80_Z80 0 +#define CPU_Z80_Z180 1 +#define CPU_Z80_Z280 2 +#define CPU_Z80_EZ80 3 +#define CPU_Z80_U880 4 +#define CPU_Z80_BM1 5 +#define CPU_Z80_EMULATOR 6 +#define CPU_Z80_CLONE 7 + +/* Must come first and be split off (SDCC bug 2771) */ + +static void ident_asm(void) +{ + __asm + xor a + ld e,e ; Seen as .LIL on eZ80 + ld hl, #0 + inc a ; part of long load on eZ80 only + ld a, #CPU_Z80_EZ80 + jr z, set_id + ld a,#0x40 + .byte 0xCB,0x37 ; from the Z280 data book + jp p, z280_detected + xor a + dec a + daa + cp #0xF9 + ld a,#CPU_Z80_Z180 + jr z, set_id + ld a,(_port_opt) + or a + jr z, no_port_idwork + di + ld bc,(_port) + in e,(c) + ld a,#1 + .db 0xED + .db 0x71 + /* out (c),0|255 */ + in a,(c) + out (c),e + ei + cp #1 + jr z, emulator_detected + inc a + ld (_z80_nmos),a + ld bc,(_port) + di + in e,(c) + and a + ld hl,#0x00FF + outi + out (c),e + ei + ld a, #1 + jr nc, no_port_idwork + ld (_outibust), a +no_port_idwork: + ld a,(#0xffff) + bit 7,(hl) + push af + pop bc + ld a,c + and #0x28 + jr nz, emulator_detected + ld a,(#0xfffe) + bit 7,(hl) + push af + pop bc + bit 5,c + jr z, emulator_detected + bit 3,c + ld a, #CPU_Z80_BM1 + jr z, set_id + ld bc,#0xffff + push bc + pop af + xor a + scf + nop + push af + pop bc + ld a,c + and #0x28 + cp #0x28 + ld a, #CPU_Z80_Z80 + jr z, set_id + ld a, #CPU_Z80_CLONE + jr set_id +emulator_detected: + ld a,#CPU_Z80_EMULATOR + jr set_id + /* TODO: separate Z280 from R800, test the many Z280 bugs */ +z280_detected: + ld a,#CPU_Z80_Z280 +set_id: + ld (_cpu_id),a + __endasm; +} + +static const int cpu_vsize = 16; +static const int cpu_psize = 16; +static const int cpu_step = -1; +static const int cpu_mhz = 0; +static uint8_t cpu_vendor, cpu_id; +static int cpu_cache = 0; +static const char cpu_fpu[] = "no"; +static const char *cpu_bugs = ""; +static const char *cpu_pm = "halt"; +static int8_t z80_nmos = -1; +static int cpu_MHz; +static const char *cpu_flags = NULL; +static uint8_t outibust; + +static char *vendor_name[] = { + "Unknown", + "Zilog", + "Clone", + "Zilog/Hitachi", + "USSR" +}; + +static char *cpu_name[] = { + "Z80", + "Z180/HD64180", + "Z280/R800", + "eZ80", + "U880", + "KP18588BM1/T34MB1", + "Emulator" +}; + +static void cpu_ident(void) +{ + ident_asm(); + switch(cpu_id) { + case CPU_Z80_Z280: /* FIXME R800.. */ + cpu_cache = 256; + /* FIXME: check divuw with bit 15 of divisor set for div bug */ + cpu_bugs = "exaf inout"; /* Also maybe some others */ + cpu_vendor = 1; + /* And on the R800 check for mul bugs */ + break; + case CPU_Z80_Z180: + cpu_vendor = 3; + cpu_pm = "halt iostop sleep systemstop"; /* Not always all of */ + break; + case CPU_Z80_Z80: + cpu_vendor = 1; + break; + case CPU_Z80_U880: + case CPU_Z80_BM1: + cpu_vendor = 4; + break; + case CPU_Z80_EMULATOR: + break; + case CPU_Z80_CLONE: + cpu_id = CPU_Z80_Z80; + cpu_vendor = 2; + break; + } + if (cpu_id == CPU_Z80_Z80 && outibust) { + cpu_vendor = 4; + cpu_id = CPU_Z80_U880; + } + if (z80_nmos == 1) + cpu_bugs = "iff"; +} + +#else +#error "unsupported CPU" +#endif + +static void do_identify(void) +{ + cpu_ident(); + printf("%-16s: 0\n", "processor"); + printf("%-16s: %s\n", "vendor_id", vendor_name[cpu_vendor]); + printf("%-16s: %s\n", "model_name", cpu_name[cpu_id]); + if (cpu_step != -1) + printf("%-16s: %d\n", "stepping", cpu_step); + if (cpu_MHz != 0) + printf("%-16s: %d\n", "cpu MHz", cpu_mhz); + if (cpu_cache != 0) + printf("%-16s: %d bytes\n", "cache size", cpu_cache); + printf("%-16s: %s\n", "fpu", cpu_fpu); + if (cpu_flags != NULL) + printf("%-16s: %s\n", "flags", cpu_flags); + if (cpu_bugs != NULL) + printf("%-16s: %s\n", "bugs", cpu_bugs); + /* TODO bogomips */ + printf("%-16s: %d bits physical, %d bits virtual\n", "address sizes", + cpu_psize, cpu_vsize); + printf("%-16s: %s\n", "power management", cpu_pm); +} + +static void usage(void) +{ + fputs("cpuinfo: [-p n]\n", stderr); + exit(EXIT_FAILURE); +} + +int main(int argc, char *argv[]) +{ + int opt; + + while((opt = getopt(argc, argv, "p:")) != -1) { + switch(opt) { + case 'p': + errno = 0; + port = strtoul(optarg, NULL, 0); + if (errno) + usage(); + port_opt = 1; + break; + default: + usage(); + } + } + if (optind != argc) + usage(); + + do_identify(); + return 0; +} + + \ No newline at end of file