SRC = main.c
SRC += cli.c cli_readline.c command.c command_tbl.c
-SRC += cmd_run.c cmd_boot.c cmd_misc.c
+SRC += cmd_run.c cmd_boot.c cmd_misc.c cmd_cpu.c
SRC += cmd_date.c cmd_mem.c cmd_gpio.c cmd_attach.c
SRC += cmd_loadihex.c cmd_loadcpm3.c cmd_sd.c cmd_fat.c
SRC += env.c con-utils.c print-utils.c getopt-min.c eval_arg.c
ASRC += ../time/system_tick.S
-SRC_Z = ../z180/hdrom.c ../z180/cfboot.c
+SRC_Z = ../z180/hdrom.c ../z180/cfboot.c ../z180/cpuinfo.c
#TARGETS = $(PROG).elf
!SIZE = |> ^ SIZE^ $(SIZE) %f |>
: foreach $(ASRC) |> !as |> {objs}
-: foreach $(SRC) | ../z180/hdrom.h ../z180/cfboot.h |> !cc |> {objs}
+: foreach $(SRC) | ../z180/hdrom.h ../z180/cfboot.h ../z180/cpuinfo.h |> !cc |> {objs}
: foreach $(SRC_Z) |> !cc -D'const=const __flash' |> {objs}
: {objs} |> !LINK |> $(PROG).elf
#undef const
-
-static void z80_load_mem(int_fast8_t verbosity,
- const FLASH unsigned char data[],
- const FLASH unsigned long *sections,
- const FLASH unsigned long address[],
- const FLASH unsigned long length_of_sections[])
-{
- uint32_t sec_base = 0;
-
- if (verbosity > 1)
- printf_P(PSTR("Loading Z180 memory... \n"));
-
- for (unsigned sec = 0; sec < *sections; sec++) {
- if (verbosity > 0) {
- printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
- address[sec],
- address[sec]+length_of_sections[sec] - 1,
- length_of_sections[sec]);
- }
-
- z80_write_block_P((const FLASH unsigned char *) &data[sec_base], /* src */
- address[sec], /* dest */
- length_of_sections[sec]); /* len */
- sec_base += length_of_sections[sec];
- }
-}
-
command_ret_t do_loadf(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
{
if (z80_bus_state() & ZST_RUNNING)
--- /dev/null
+/*
+ * (C) Copyright 2018 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#include "cmd_cpu.h"
+//#include <ctype.h>
+//#include <util/atomic.h>
+
+#include "z80-if.h"
+#include "con-utils.h"
+//#include "env.h"
+//#include "eval_arg.h"
+//#include "getopt-min.h"
+//#include "debug.h"
+
+/* hack to get Z180 loadfile into flash memory */
+#define const const FLASH
+#include "../z180/cpuinfo.h"
+#undef const
+
+
+static const FLASH char * const FLASH cpu_strings[] = {
+ FSTR("Unknown CPU"),
+ FSTR("8080"),
+ FSTR("8085"),
+ FSTR("Z80"),
+ FSTR("x180"),
+ FSTR("HD64180"),
+ FSTR("Z80180"),
+ FSTR("Z80S180"),
+};
+
+command_ret_t do_cpuchk(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED)
+{
+ uint8_t done = 0;
+ uint8_t cputype;
+ ERRNUM err = ESUCCESS;
+ uint8_t ram_save[cpuinfo_length];
+
+ if (z80_bus_state() & ZST_RUNNING) {
+ err = ERUNNING;
+ } else {
+ z80_bus_request_or_exit();
+ z80_read_block(ram_save, 0, cpuinfo_length);
+ z80_load_mem(0, cpuinfo,
+ &cpuinfo_sections,
+ cpuinfo_address,
+ cpuinfo_length_of_sections);
+ z80_bus_cmd(Release);
+
+ if (argv[1] && (argv[1][0] == 'n'))
+ goto donot;
+
+ z80_bus_cmd(Run);
+
+ clear_ctrlc(); /* forget any previous Control C */
+ while (done != 0xFF) {
+ _delay_ms(8);
+ /* check for ctrl-c to abort... */
+ if (had_ctrlc() || ctrlc()) {
+ err = EINTR;
+ break;
+ }
+ z80_bus_cmd(Request);
+ done = z80_read(3);
+ if (done == 0xFF)
+ cputype = z80_read(4);
+ z80_bus_cmd(Release);
+ }
+ z80_bus_cmd(Reset);
+ z80_bus_cmd(Request);
+// z80_write_block(ram_save, 0, cpuinfo_length);
+ z80_bus_cmd(Release);
+ }
+
+donot:
+
+ if (err)
+ cmd_error(CMD_RET_FAILURE, err, NULL);
+
+ if (done == 0xFF) {
+ if (cputype >= ARRAY_SIZE(cpu_strings))
+ cputype = 0;
+ printf_P(PSTR("Detected CPU: %S\n"), cpu_strings[cputype]);
+ }
+
+ return CMD_RET_SUCCESS;
+}
#include "command.h"
#include "cmd_mem.h"
#include "cmd_boot.h"
+#include "cmd_cpu.h"
#include "cmd_misc.h"
#include "cmd_date.h"
#include "cmd_run.h"
cmd_tbl_env
),
+CMD_TBL_ITEM(
+ chkcpu, CONFIG_SYS_MAXARGS, CTBL_RPT, do_cpuchk,
+ "Check CPU",
+ ""
+),
CMD_TBL_ITEM(
loadf, 1, 0, do_loadf,
"load srec_cat prepared image from controller flash",
return addr;
}
+/*--------------------------------------------------------------------------*/
+
void z80_write(uint32_t addr, uint8_t data)
{
z80_setaddress(addr);
Z80_O_MREQ = 1;
}
+/*--------------------------------------------------------------------------*/
/*
0179' rx.bs_mask: ds 1 ; (buf_len - 1)
z80_write(fifo_dsc[f].base+FIFO_INDEX_IN, fifo_dsc[f].idx_in);
z80_bus_cmd(Release);
}
+
+/*--------------------------------------------------------------------------*/
+
+void z80_load_mem(int_fast8_t verbosity,
+ const FLASH unsigned char data[],
+ const FLASH unsigned long *sections,
+ const FLASH unsigned long address[],
+ const FLASH unsigned long length_of_sections[])
+{
+ uint32_t sec_base = 0;
+
+ if (verbosity > 1)
+ printf_P(PSTR("Loading Z180 memory... \n"));
+
+ for (unsigned sec = 0; sec < *sections; sec++) {
+ if (verbosity > 0) {
+ printf_P(PSTR(" From: 0x%.5lX to: 0x%.5lX (%5li bytes)\n"),
+ address[sec],
+ address[sec]+length_of_sections[sec] - 1,
+ length_of_sections[sec]);
+ }
+
+ z80_write_block_P((const FLASH unsigned char *) &data[sec_base], /* src */
+ address[sec], /* dest */
+ length_of_sections[sec]); /* len */
+ sec_base += length_of_sections[sec];
+ }
+}
--- /dev/null
+/*
+ * (C) Copyright 2018 Leo C. <erbl259-lmu@yahoo.de>
+ *
+ * SPDX-License-Identifier: GPL-2.0
+ */
+
+#ifndef CMD_CPU_H
+#define CMD_CPU_H
+
+#include "command.h"
+
+command_ret_t do_cpuchk(cmd_tbl_t *, uint_fast8_t, int, char * const []);
+
+#endif /* CMD_CPU_H */
int z80_memfifo_getc(const fifo_t f);
uint8_t z80_memfifo_getc_wait(const fifo_t f);
void z80_memfifo_putc(fifo_t f, uint8_t val);
+
+void z80_load_mem(int_fast8_t verbosity, const FLASH unsigned char data[],
+ const FLASH unsigned long *sections,
+ const FLASH unsigned long address[],
+ const FLASH unsigned long length_of_sections[]);
PROG = hdrom
CFBOOT = cfboot
+CPUINFO = cpuinfo
SRC = init.180
SRC += ddtz.180
: $(CFBOOT).180 |> $(AS) -%B/HFS |> %B.hex | %B.lst
: $(CFBOOT).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(CFBOOT).c | $(CFBOOT).h
+: $(CPUINFO).180 |> $(AS) -%B/HFS |> %B.hex | %B.lst
+: $(CPUINFO).hex |> srec_cat -o %o -c_array %B -C_COMpressed -include %f -Intel |> $(CPUINFO).c | $(CPUINFO).h
+
#COMMAND="$(AS) -%B/$(AS_OPT)"; \
--- /dev/null
+ .z80 ; for M80, ignored by SLR assembler\r
+ include z180reg.inc\r
+\r
+RUN_TPA equ 0\r
+\r
+UUNKNOWN equ 0 ;Unknown CPU\r
+U8080 equ 1 ;8080\r
+U8085 equ 2 ;8085\r
+UZ80 equ 3 ;Z80\r
+UX180 equ 4 ;HD64180 or higher\r
+UHD64180 equ 5 ;HD64180\r
+UZ80180 equ 6 ;Z80180\r
+UZ8S180 equ 7 ;Z8S180, Z8L180\r
+\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+\r
+ if RUN_TPA\r
+base equ 0100h\r
+ else\r
+base equ 0\r
+ endif\r
+\r
+\r
+ aseg\r
+ org base\r
+ jp start\r
+\r
+done: db 0\r
+result: db 0\r
+\r
+;-------------------------------------------------------------------------------\r
+; Read internal register at address in L and IOBASE in H.\r
+;\r
+\r
+reg_in:\r
+ ld a,h\r
+ add a,l\r
+ ld c,a\r
+ ld b,0\r
+ in a,(c)\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; Write internal register at address in L and IOBASE in H.\r
+;\r
+\r
+reg_out:\r
+ ld b,a\r
+ ld a,h\r
+ add a,l\r
+ ld c,a\r
+ ld a,b\r
+ ld b,0\r
+ out (c),a\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; Check if register C exists. D holds mask of bit to test.\r
+; return nz, if register exists\r
+\r
+chk_reg:\r
+ call reg_in\r
+ cp 0ffh\r
+ ret nz ;\r
+\r
+ ; check, if register is changeable\r
+\r
+ xor d ; set bit(s) in register to 0\r
+ call reg_out\r
+ call reg_in ; get it back\r
+ ex af,af'\r
+ ld a,0ffh ; set to register original state\r
+ call reg_out\r
+ ex af,af'\r
+ cpl\r
+ and d\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+; Check CPU\r
+;\r
+;\r
+; return:\r
+; E = 0 Unknown\r
+; E = 1 8080\r
+; E = 2 8085\r
+; E = 3 Z80\r
+; E = 4 HD64180 or higher\r
+; E = 5 HD64180\r
+; E = 6 Z80180\r
+; E = 7 Z8S180, Z8L180\r
+;\r
+;-------------------------------------------------------------------------------\r
+; Registers only in Z180+, not in HD64180\r
+; 3E OMCR\r
+;\r
+; Registers only in Z8S180/Z8L180\r
+; 12 ASEXT0\r
+; 13 ASEXT1\r
+; 1A ASTC0L\r
+; 1B ASTC0H\r
+; 1C ASTC1L\r
+; 1D ASTC1H\r
+; 1E CMR\r
+; 1F CCR\r
+; 2D IAR1B\r
+;\r
+; Reserved registers\r
+; 11\r
+; 19\r
+; 35\r
+; 37\r
+; 3B - 3D\r
+\r
+check:\r
+ ld e,U8080 ; Init return val, assume 8080\r
+ xor a\r
+ dec a ; 00 --> 0FFH 8080/8085: even parity; Z80+: No overflow\r
+ jp po,chk_z80 ; Z80+ if P/V flag reset\r
+\r
+ ; The 8085 logical AND instructions always set the auxiliary flag ON.\r
+ ; The 8080 logical AND instructions set the flag to reflect the\r
+ ; logical OR of bit 3 of the values involved in the AND operation.\r
+ ; (8080/8085 ASSEMBLY LANGUAGE PROGRAMMING MANUAL, 1977, 1978)\r
+\r
+ xor a\r
+ and a ; 8085 sets, 8080 resets half carry.\r
+ daa ; A=06 (8085) or A=00 (8080)\r
+ ret z\r
+ inc e\r
+ ret\r
+\r
+chk_z80:\r
+ ld e,UZ80 ; Assume Z80\r
+ daa ; Z80: 099H, x180+: 0F9H\r
+ cp 99h ; Result on 180 type cpus is F9 here. Thanks Hitachi\r
+ ret z\r
+ inc e ; x180\r
+\r
+ ; At least Hitachi HD64180\r
+ ; Test differences in certain internal registers\r
+ ; to determine the 180 variant.\r
+ ; First, search the internal register bank.\r
+\r
+ ld h,00H ; I/O Base\r
+find_base_loop:\r
+ ld l,icr\r
+ call reg_in\r
+ and 11011111b ; mask I/O Stop bit\r
+ xor h\r
+ cp 01FH\r
+ jr nz,nxt_base\r
+\r
+ ;TODO: additional plausibility checks\r
+\r
+ jr z,base_found\r
+nxt_base:\r
+ ld a,h\r
+ add a,040H\r
+ ld h,a\r
+ jr nc,find_base_loop\r
+ ret ;I/O registers not found\r
+\r
+ ; Register (base) found.\r
+\r
+base_found:\r
+ inc e ; HD64180\r
+ ld l,omcr ; Check, if CPU has OMCR register\r
+ ld d,M_IOC ;\r
+ call chk_reg ;\r
+ ret z ; Register does not exist. It's a HD64180\r
+\r
+ inc e ; Z80180\r
+ ld l,cmr ; Check, if CPU has CMR register\r
+ ld d,M_LNC ;\r
+ call chk_reg ;\r
+ ret z ; register does not exist. It's a Z80180\r
+\r
+ inc e ; S180/L180 (class) detected.\r
+\r
+ ret\r
+\r
+;-------------------------------------------------------------------------------\r
+\r
+start:\r
+ ld sp,stack\r
+ call check\r
+\r
+ ld hl,result\r
+ ld (hl),e\r
+ dec hl\r
+ ld (hl),0ffH\r
+ halt\r
+ jp $-1\r
+\r
+ rept 8\r
+ dw 0\r
+ endm\r
+stack:\r
+ end\r
+\r
+; vim:set ts=8 noet nowrap\r