Alpha release candidate rc1
This commit is contained in:
BIN
software/FusionX/bin/k64fcpu
vendored
BIN
software/FusionX/bin/k64fcpu
vendored
Binary file not shown.
BIN
software/FusionX/bin/sharpbiter
vendored
BIN
software/FusionX/bin/sharpbiter
vendored
Binary file not shown.
BIN
software/FusionX/bin/z80ctrl
vendored
BIN
software/FusionX/bin/z80ctrl
vendored
Binary file not shown.
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
BIN
software/FusionX/modules/ttymzdrv.ko
vendored
Binary file not shown.
BIN
software/FusionX/modules/z80drv.ko
vendored
BIN
software/FusionX/modules/z80drv.ko
vendored
Binary file not shown.
46
software/FusionX/src/ttymz/Makefile
vendored
46
software/FusionX/src/ttymz/Makefile
vendored
@@ -1,15 +1,17 @@
|
||||
# Select the target host.
|
||||
#MODEL := MZ2000
|
||||
#MODEL := MZ700
|
||||
#DEBUG := y
|
||||
MODEL := MZ80A
|
||||
#MODEL := MZ2000
|
||||
#MODEL := MZ700
|
||||
#MODEL := MZ80A
|
||||
#MODEL := PCW8XXX
|
||||
#MODEL := PCW9XXX
|
||||
KERNEL := $(PWD)/../../../linux/kernel
|
||||
FUSIONX := $(PWD)/../..
|
||||
CROSS := arm-linux-gnueabihf-
|
||||
CTRLINC = -IZeta/API -IZ80/API -DTARGET_HOST_$(MODEL)=1
|
||||
|
||||
ccflags-y = -O2 -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__ -DTARGET_HOST_$(MODEL)=1
|
||||
ifeq ($(DEBUG),y)
|
||||
ccflags-y += -DTTYMZ_DEBUG
|
||||
else
|
||||
ccflags-y += -O2 -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__
|
||||
endif
|
||||
obj-m += ttymzdrv.o
|
||||
ttymzdrv-objs += ttymz.o z80io.o sharpmz.o
|
||||
@@ -18,16 +20,42 @@ ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||
ttymzdrv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||
|
||||
all:
|
||||
@echo "Specify target host, ie. make <host>"
|
||||
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||
|
||||
all:
|
||||
MZ80A: MODEL_MZ80A
|
||||
MZ700: MODEL_MZ700
|
||||
MZ2000: MODEL_MZ2000
|
||||
PCW8XXX: MODEL_PCW8XXX
|
||||
PCW9XXX: MODEL_PCW9XXX
|
||||
|
||||
MODEL_MZ80A:
|
||||
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||
MODEL_MZ700:
|
||||
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||
MODEL_MZ2000:
|
||||
$(MAKE) MODEL=MZ2000 BUILD_MZ2000
|
||||
MODEL_PCW8XXX:
|
||||
$(MAKE) MODEL=PCW8XXX BUILD_PCW8XXX
|
||||
MODEL_PCW9XXX:
|
||||
$(MAKE) MODEL=PCW8XXX BUILD_PCW9XXX
|
||||
|
||||
BUILD_MZ80A: kmod
|
||||
BUILD_MZ700: kmod
|
||||
BUILD_MZ2000: kmod
|
||||
BUILD_PCW8XXX: kmod
|
||||
BUILD_PCW9XXX: kmod
|
||||
|
||||
kmod:
|
||||
@echo ""
|
||||
@echo "Build TTYMZ driver for host: $(MODEL)"
|
||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||
@echo ""
|
||||
|
||||
install:
|
||||
@echo "Copy kernel driver..."
|
||||
@cp ttymz.ko $(FUSIONX)/modules/
|
||||
@cp ttymzdrv.ko $(FUSIONX)/modules/
|
||||
|
||||
clean:
|
||||
make -C $(KERNEL) M=$(PWD) clean
|
||||
@rm -f ttymz
|
||||
|
||||
@@ -542,21 +542,21 @@ static t_scanCodeMap scanCodeMap[] = {
|
||||
CTRL_G , // ^G F7
|
||||
CTRL_H , // ^H F8
|
||||
// S5 28 - 2F
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
HOTKEY_ORIGINAL, // 1 - Hotkey to invoke original mode.
|
||||
HOTKEY_RFS40, // 2 - Hotkey to invoke RFS 40 mode.
|
||||
HOTKEY_TZFS, // 3 - Hotkey to invoke TZFS mode.
|
||||
HOTKEY_LINUX, // 4 - Hotkey to invoke Linux mode.
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
// S6 30 - 37 (ERROR? 7 VALUES ONLY!!)
|
||||
NOKEY , // ^YEN E6
|
||||
CTRL_CAPPA , // ^ EF
|
||||
NOKEY , // ^YEN E6
|
||||
CTRL_CAPPA , // ^ EF
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
CTRL_UNDSCR , // ^,
|
||||
CTRL_UNDSCR , // ^,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
// S7 - 38 - 3F
|
||||
@@ -567,22 +567,22 @@ static t_scanCodeMap scanCodeMap[] = {
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
CTRL_SLASH , // ^/ EE
|
||||
CTRL_SLASH , // ^/ EE
|
||||
// S8 40 - 47 - modifier keys.
|
||||
NOKEY , // BREAK - CTRL+BREAK - not yet assigned
|
||||
NOKEY , // CTRL
|
||||
NOKEY , // BREAK - CTRL+BREAK - not yet assigned
|
||||
NOKEY , // CTRL
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY , // SHIFT
|
||||
NOKEY , // SHIFT
|
||||
// S9 48 - 4F - Function keys.
|
||||
FUNC1 , // Function key F1
|
||||
FUNC2 , // Function key F2
|
||||
FUNC3 , // Function key F3
|
||||
FUNC4 , // Function key F4
|
||||
FUNC5 , // Function key F5
|
||||
FUNC1 , // Function key F1
|
||||
FUNC2 , // Function key F2
|
||||
FUNC3 , // Function key F3
|
||||
FUNC4 , // Function key F4
|
||||
FUNC5 , // Function key F5
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY
|
||||
@@ -681,8 +681,8 @@ static t_scanCodeMap scanCodeMap[] = {
|
||||
NOKEY
|
||||
}}
|
||||
};
|
||||
#endif
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
|
||||
#elif (TARGET_HOST_MZ80A == 1)
|
||||
static t_scanCodeMap scanCodeMap[] = {
|
||||
// MZ_80A NO SHIFT
|
||||
{{
|
||||
@@ -1151,6 +1151,477 @@ static t_scanCodeMap scanCodeMap[] = {
|
||||
}}
|
||||
};
|
||||
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
static t_scanCodeMap scanCodeMap[] = {
|
||||
// MZ_2000 NO SHIFT
|
||||
{{
|
||||
// S0 00 - 07
|
||||
NOKEY , // BREAK/CTRL
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
GRAPHKEY , // GRAPH
|
||||
NOKEY , // SHIFT
|
||||
// S1 08 - 0F
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
'w' , // w
|
||||
'q' , // q
|
||||
'a' , // a
|
||||
BACKS , // DELETE
|
||||
NOKEY , // NULL
|
||||
'z' , // z
|
||||
// S2 10 - 17
|
||||
'4' , // 4
|
||||
'3' , // 3
|
||||
'r' , // r
|
||||
'e' , // e
|
||||
'd' , // d
|
||||
's' , // s
|
||||
'x' , // x
|
||||
'c' , // c
|
||||
// S3 18 - 1F
|
||||
'6' , // 6
|
||||
'5' , // 5
|
||||
'y' , // y
|
||||
't' , // t
|
||||
'g' , // g
|
||||
'f' , // f
|
||||
'v' , // v
|
||||
'b' , // b
|
||||
// S4 20 - 27
|
||||
'8' , // 8
|
||||
'7' , // 7
|
||||
'i' , // i
|
||||
'u' , // u
|
||||
'j' , // j
|
||||
'h' , // h
|
||||
'n' , // n
|
||||
' ' , // SPACE
|
||||
// S5 28 - 2F
|
||||
'0' , // 0
|
||||
'9' , // 9
|
||||
'p' , // p
|
||||
'o' , // o
|
||||
'l' , // l
|
||||
'k' , // k
|
||||
',' , // ,
|
||||
'm' , // m
|
||||
// S6 30 - 37
|
||||
'^' , // ^
|
||||
'-' , // -
|
||||
'[' , // [
|
||||
'@' , // @
|
||||
':' , // :
|
||||
';' , // ;
|
||||
'/' , // /
|
||||
'.' , // .
|
||||
// S7 38 - 3F
|
||||
HOMEKEY , // HOME.
|
||||
'\\' , // Backslash
|
||||
CURSRIGHT, // CURSOR RIGHT
|
||||
CURSUP , // CURSOR UP
|
||||
CR , // CR
|
||||
']' , // ]
|
||||
NOKEY , //
|
||||
'?' , // ?
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
'8' , // Keypad 8
|
||||
'7' , // 7
|
||||
'5' , // 5
|
||||
'4' , // 4
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
DBLZERO , // 00
|
||||
'0' , // 0
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
'+' , // +
|
||||
'0' , // 9
|
||||
'-' , // -
|
||||
'6' , // 6
|
||||
NOKEY , //
|
||||
'3' , // 3
|
||||
NOKEY ,
|
||||
'.' // .
|
||||
}},
|
||||
// MZ_2000 CAPS LOCK
|
||||
{{
|
||||
// S0 00 - 07
|
||||
NOKEY , // BREAK/CTRL
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
ALPHAKEY , // GRAPH
|
||||
NOKEY , // SHIFT
|
||||
// S1 08 - 0F
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
'W' , // W
|
||||
'Q' , // Q
|
||||
'A' , // A
|
||||
BACKS , // DELETE
|
||||
NOKEY , // NULL
|
||||
'Z' , // Z
|
||||
// S2 10 - 17
|
||||
'4' , // 4
|
||||
'3' , // 3
|
||||
'R' , // R
|
||||
'E' , // E
|
||||
'D' , // D
|
||||
'S' , // S
|
||||
'X' , // X
|
||||
'C' , // C
|
||||
// S3 18 - 1F
|
||||
'6' , // 6
|
||||
'5' , // 5
|
||||
'Y' , // Y
|
||||
'T' , // T
|
||||
'G' , // G
|
||||
'F' , // F
|
||||
'V' , // V
|
||||
'B' , // B
|
||||
// S4 20 - 27
|
||||
'8' , // 8
|
||||
'7' , // 7
|
||||
'I' , // I
|
||||
'U' , // U
|
||||
'J' , // J
|
||||
'H' , // H
|
||||
'N' , // N
|
||||
' ' , // SPACE
|
||||
// S5 28 - 2F
|
||||
'0' , // 0
|
||||
'9' , // 9
|
||||
'P' , // P
|
||||
'O' , // O
|
||||
'L' , // L
|
||||
'K' , // K
|
||||
',' , // ,
|
||||
'M' , // M
|
||||
// S6 30 - 37
|
||||
'^' , // ^
|
||||
'-' , // -
|
||||
'[' , // [
|
||||
'@' , // @
|
||||
':' , // :
|
||||
';' , // ;
|
||||
'/' , // /
|
||||
'.' , // .
|
||||
// S7 38 - 3F
|
||||
HOMEKEY , // HOME.
|
||||
'\\' , // Backslash
|
||||
CURSRIGHT, // CURSOR RIGHT
|
||||
CURSUP , // CURSOR UP
|
||||
CR , // CR
|
||||
']' , // ]
|
||||
NOKEY , //
|
||||
'?' , // ?
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
'8' , // Keypad 8
|
||||
'7' , // 7
|
||||
'5' , // 5
|
||||
'4' , // 4
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
DBLZERO , // 00
|
||||
'0' , // 0
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
'+' , // +
|
||||
'0' , // 9
|
||||
'-' , // -
|
||||
'6' , // 6
|
||||
NOKEY , //
|
||||
'3' , // 3
|
||||
NOKEY ,
|
||||
'.' // .
|
||||
}},
|
||||
// MZ_2000 SHIFT LOCK.
|
||||
{{
|
||||
// S0 00 - 07
|
||||
NOKEY , // BREAK/CTRL
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
ALPHAKEY , // GRAPH
|
||||
NOKEY , // SHIFT
|
||||
// S1 08 - 0F
|
||||
'"' , // "
|
||||
'!' , // !
|
||||
'W' , // W
|
||||
'Q' , // Q
|
||||
'A' , // A
|
||||
INSERT , // INSERT
|
||||
NOKEY , // NULL
|
||||
'Z' , // Z
|
||||
// S2 10 - 17
|
||||
'$' , // $
|
||||
'#' , // #
|
||||
'R' , // R
|
||||
'E' , // E
|
||||
'D' , // D
|
||||
'S' , // S
|
||||
'X' , // X
|
||||
'C' , // C
|
||||
// S3 18 - 1F
|
||||
'&' , // &
|
||||
'%' , // %
|
||||
'Y' , // Y
|
||||
'T' , // T
|
||||
'G' , // G
|
||||
'F' , // F
|
||||
'V' , // V
|
||||
'B' , // B
|
||||
// S4 20 - 27
|
||||
'(' , // (
|
||||
'\'' , // '
|
||||
'I' , // I
|
||||
'U' , // U
|
||||
'J' , // J
|
||||
'H' , // H
|
||||
'N' , // N
|
||||
' ' , // SPACE
|
||||
// S5 28 - 2F
|
||||
'_' , // _
|
||||
')' , // )
|
||||
'P' , // P
|
||||
'O' , // O
|
||||
'L' , // L
|
||||
'K' , // K
|
||||
'<' , // <
|
||||
'M' , // M
|
||||
// S6 30 - 37
|
||||
'~' , // ~
|
||||
'=' , // =
|
||||
'{' , // {
|
||||
'`' , // `
|
||||
'*' , // *
|
||||
'+' , // +
|
||||
NOKEY , //
|
||||
'>' , // >
|
||||
// S7 38 - 3F
|
||||
CLRKEY , // CLR.
|
||||
'|' , // |
|
||||
CURSLEFT , // CURSOR LEFT
|
||||
CURSDOWN , // CURSOR DOWN
|
||||
CR , // CR
|
||||
'}' , // }
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
'8' , // Keypad 8
|
||||
'7' , // 7
|
||||
'5' , // 5
|
||||
'4' , // 4
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
DBLZERO , // 00
|
||||
'0' , // 0
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
'+' , // +
|
||||
'0' , // 9
|
||||
'-' , // -
|
||||
'6' , // 6
|
||||
NOKEY , //
|
||||
'3' , // 3
|
||||
NOKEY ,
|
||||
'.' // .
|
||||
}},
|
||||
// MZ_2000 CONTROL CODE
|
||||
{{
|
||||
// S0 00 - 07
|
||||
NOKEY , // BREAK/CTRL
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
ALPHAGRAPHKEY, // GRAPH
|
||||
NOKEY , // SHIFT
|
||||
// S1 08 - 0F
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_W , // CTRL_W
|
||||
CTRL_Q , // CTRL_Q
|
||||
CTRL_A , // CTRL_A
|
||||
DELETE , // DELETE
|
||||
NOKEY , // NULL
|
||||
CTRL_Z , // CTRL_Z
|
||||
// S2 10 - 17
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_R , // CTRL_R
|
||||
CTRL_E , // CTRL_E
|
||||
CTRL_D , // CTRL_D
|
||||
CTRL_S , // CTRL_S
|
||||
CTRL_X , // CTRL_X
|
||||
CTRL_C , // CTRL_C
|
||||
// S3 18 - 1F
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_Y , // CTRL_Y
|
||||
CTRL_T , // CTRL_T
|
||||
CTRL_G , // CTRL_G
|
||||
CTRL_F , // CTRL_F
|
||||
CTRL_V , // CTRL_V
|
||||
CTRL_B , // CTRL_B
|
||||
// S4 20 - 27
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_I , // CTRL_I
|
||||
CTRL_U , // CTRL_U
|
||||
CTRL_J , // CTRL_J
|
||||
CTRL_H , // CTRL_H
|
||||
CTRL_N , // CTRL_N
|
||||
' ' , // SPACE
|
||||
// S5 28 - 2F
|
||||
CTRL_UNDSCR, // CTRL+_
|
||||
NOKEY , //
|
||||
CTRL_P , // CTRL_P
|
||||
CTRL_O , // CTRL_O
|
||||
CTRL_L , // CTRL_L
|
||||
CTRL_K , // CTRL_K
|
||||
NOKEY , //
|
||||
CTRL_M , // CTRL_M
|
||||
// S6 30 - 37
|
||||
CTRL_CAPPA, // CTRL+^
|
||||
NOKEY , //
|
||||
CTRL_LB , // CTRL+[
|
||||
CTRL_AT , // CTRL+@
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_SLASH, // CTRL+/
|
||||
NOKEY , //
|
||||
// S7 38 - 3F
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
CTRL_RB , // CTRL+]
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
NOKEY , // Keypad 8
|
||||
NOKEY , // 7
|
||||
NOKEY , // 5
|
||||
HOTKEY_LINUX, // 4 - Hotkey to invoke Linux mode.
|
||||
HOTKEY_RFS40, // 2 - Hotkey to invoke RFS 40 mode.
|
||||
HOTKEY_RFS80, // 1 - Hotkey to invoke RFS 80 mode.
|
||||
NOKEY , // 00
|
||||
HOTKEY_ORIGINAL, // 0 - Hotkey to invoke original mode.
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
NOKEY , // +
|
||||
NOKEY , // 9
|
||||
NOKEY , // -
|
||||
NOKEY , // 6
|
||||
NOKEY , //
|
||||
HOTKEY_TZFS, // 3 - Hotkey to invoke TZFS mode.
|
||||
NOKEY ,
|
||||
NOKEY // .
|
||||
}},
|
||||
// MZ_2000 KANA
|
||||
{{
|
||||
// S0 00 - 07
|
||||
NOKEY , // BREAK/CTRL
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
NOKEY , //
|
||||
GRAPHKEY , // DAKU TEN
|
||||
NOKEY , //
|
||||
// S1 08 - 0F
|
||||
0x35 , // HA
|
||||
0x77 , // TA
|
||||
0xD7 , // WA
|
||||
0xB3 , // YO
|
||||
0xB7 , // HANDAKU
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
NOKEY ,
|
||||
// S2 10 - 17
|
||||
0x7C , // KA
|
||||
0x70 , // KE
|
||||
0x41 , // SHI
|
||||
0x31 , // KO
|
||||
0x39 , // HI
|
||||
0xA6 , // TE
|
||||
0x78 , // KI
|
||||
0xDD , // CHI
|
||||
// S3 18 - 1F
|
||||
0x3D , // FU
|
||||
0x5D , // MI
|
||||
0x6C , // MU
|
||||
0x56 , // ME
|
||||
0x1D , // RHI
|
||||
0x33 , // RA
|
||||
0xD5 , // HE
|
||||
0xB1 , // HO
|
||||
// S4 20 - 27
|
||||
0x46 , // SA
|
||||
0x6E , // TO
|
||||
0xD9 , // THU
|
||||
0x48 , // SU
|
||||
0x74 , // KU
|
||||
0x43 , // SE
|
||||
0x4C , // SO
|
||||
0x73 , // MA
|
||||
// S5 28 - 2F
|
||||
0x3F , // A
|
||||
0x36 , // I
|
||||
0x7E , // U
|
||||
0x3B , // E
|
||||
0x7A , // O
|
||||
0x1E , // NA
|
||||
0x5F , // NI
|
||||
0xA2 , // NU
|
||||
// S6 30 - 37
|
||||
0xD3 , // YO
|
||||
0x9F , // YU
|
||||
0xD1 , // YA
|
||||
0x00 , // SPACE
|
||||
0x9D , // NO
|
||||
0xA3 , // NE
|
||||
0xD0 , // RU
|
||||
0xB9 , // RE
|
||||
// S7 38 - 3F
|
||||
0xC6 , // ?CLR
|
||||
0xC5 , // ?HOME
|
||||
0xC2 , // ?CURSOR UP
|
||||
0xC1 , // ?CURSOR DOWN
|
||||
0xC3 , // ?CURSOR RIGHT
|
||||
0xC4 , // ?CURSOR LEFT
|
||||
0xBB , // DASH
|
||||
0xBE , // RO
|
||||
// S8 40 - 47 - Keypad keys.
|
||||
'8' , // Keypad 8
|
||||
'7' , // 7
|
||||
'5' , // 5
|
||||
'4' , // 4
|
||||
'2' , // 2
|
||||
'1' , // 1
|
||||
DBLZERO , // 00
|
||||
'0' , // 0
|
||||
// S9 48 - 4F - Keypad keys.
|
||||
'+' , // +
|
||||
'0' , // 9
|
||||
'-' , // -
|
||||
'6' , // 6
|
||||
NOKEY , //
|
||||
'3' , // 3
|
||||
NOKEY ,
|
||||
'.' // .
|
||||
}}
|
||||
};
|
||||
|
||||
#else
|
||||
#error "Unknown host, no keyboard map configured."
|
||||
#endif
|
||||
|
||||
// Mapping table of sharp special control keys to ANSI ESCape sequences.
|
||||
@@ -1203,8 +1674,36 @@ static t_ansiKeyMap ansiKeySeq[] = {
|
||||
|
||||
// Colour map for the Ansi Terminal.
|
||||
const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
#endif
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
|
||||
#elif (TARGET_HOST_MZ80A == 1)
|
||||
// Static structures for controlling and managing hardware features.
|
||||
// Display control structure. Used to manage the display including the Ansi Terminal.
|
||||
const t_displayBuffer displayDefault = { .displayAttr = 0x71, .backingRow = 0, .displayCol = 0, .displayRow = 0, .maxBackingRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS),
|
||||
.maxDisplayRow = VC_MAX_ROWS, .maxBackingCol = 80, .useAnsiTerm = 1, .lineWrap = 0, .inDebug = 0
|
||||
};
|
||||
|
||||
// Keyboard control structure. Used to manage keyboard sweep, mapping and store.
|
||||
const t_keyboard keyboardDefault = { .holdTimer = 0L, .autorepeat = 0, .mode = KEYB_LOWERCASE, .cursorOn = 1, .flashTimer = 0L, .keyBuf[0] = 0x00, .keyBufPtr = 0,
|
||||
.mode = KEYB_LOWERCASE, .dualmode = KEYB_DUAL_GRAPH
|
||||
};
|
||||
|
||||
// Audio control structure. Used to manage audio output.
|
||||
const t_audio audioDefault = { .audioStopTimer = 0
|
||||
};
|
||||
|
||||
|
||||
// AnsiTerminal control structure. Used to manage the inbuilt Ansi Terminal.
|
||||
const t_AnsiTerm ansitermDefault = { .state = ANSITERM_ESC, .charcnt = 0, .paramcnt = 0, .setDisplayMode = 0, .setExtendedMode = 0, .saveRow = 0, .saveCol = 0,
|
||||
};
|
||||
|
||||
// Module control structure.
|
||||
const t_control ctrlDefault = { .suspendIO = 0, .debug = 0
|
||||
};
|
||||
|
||||
// Colour map for the Ansi Terminal.
|
||||
const unsigned char ansiColourMap[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
|
||||
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
// Static structures for controlling and managing hardware features.
|
||||
// Display control structure. Used to manage the display including the Ansi Terminal.
|
||||
const t_displayBuffer displayDefault = { .displayAttr = 0x71, .backingRow = 0, .displayCol = 0, .displayRow = 0, .maxBackingRow = (VC_DISPLAY_BUFFER_SIZE / VC_MAX_COLUMNS),
|
||||
@@ -1249,6 +1748,11 @@ static t_ansiKeyMap ansiKeySeq[] = {
|
||||
//
|
||||
uint8_t mzInitMBHardware(void)
|
||||
{
|
||||
#if (TARGET_HOST_MZ700 == 1)
|
||||
// Ensure memory paging is set to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
#endif
|
||||
|
||||
// From the 1Z-013A monitor code, initialise the 8255 PIO.
|
||||
//
|
||||
WRITE_HARDWARE(1, MBADDR_KEYPF, 0x8A); // 10001010 CTRL WORD MODE0
|
||||
@@ -1312,10 +1816,11 @@ void mzBeep(uint32_t freq, uint32_t timeout)
|
||||
// Locals.
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
uint16_t freqDiv = TIMER_8253_MZ80A_FREQ/(freq*2);
|
||||
#else
|
||||
#elif (TARGET_HOST_MZ700 == 1)
|
||||
uint16_t freqDiv = TIMER_8253_MZ700_FREQ/freq;
|
||||
#endif
|
||||
|
||||
#if (TARGET_HOST_MZ2000 == 0)
|
||||
// Setup the 8253 Timer 0 to output a sound, enable output to amplifier and set timeout.
|
||||
WRITE_HARDWARE(0, MBADDR_CONTF, 0x34 ); // Timer 0 to square wave generator, load LSB first.
|
||||
WRITE_HARDWARE(0, MBADDR_CONT0, (freqDiv&0xff) );
|
||||
@@ -1324,6 +1829,7 @@ void mzBeep(uint32_t freq, uint32_t timeout)
|
||||
|
||||
// Set a 500ms timeout on the sound to create beep effect.
|
||||
audio.audioStopTimer = timeout == 0 ? 11 : (timeout/10)+1; // Each unit is 10ms, valid range 1..n
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -2964,8 +3470,33 @@ uint8_t mzSweepKeys(void)
|
||||
{
|
||||
keyboard.shiftKey = 0;
|
||||
}
|
||||
#endif
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
|
||||
#elif (TARGET_HOST_MZ80A == 1)
|
||||
// Check for modifiers.
|
||||
//
|
||||
if((keyboard.scanbuf[0][0] & 0x01) == 0)
|
||||
{
|
||||
keyboard.shiftKey = 1;
|
||||
} else
|
||||
{
|
||||
keyboard.shiftKey = 0;
|
||||
}
|
||||
if((keyboard.scanbuf[0][0] & 0x80) == 0 && keyboard.shiftKey == 0)
|
||||
{
|
||||
keyboard.ctrlKey = 1;
|
||||
} else
|
||||
{
|
||||
keyboard.ctrlKey = 0;
|
||||
}
|
||||
if((keyboard.scanbuf[0][0] & 0x80) == 0 && keyboard.shiftKey == 1)
|
||||
{
|
||||
keyboard.breakKey = 1;
|
||||
} else
|
||||
{
|
||||
keyboard.breakKey = 0;
|
||||
}
|
||||
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
// Check for modifiers.
|
||||
//
|
||||
if((keyboard.scanbuf[0][0] & 0x01) == 0)
|
||||
|
||||
348
software/FusionX/src/ttymz/sharpmz.h
vendored
348
software/FusionX/src/ttymz/sharpmz.h
vendored
@@ -36,182 +36,210 @@
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||
#define TARGET_HOST_MZ80A 1 // MZ80A
|
||||
// Build time target. Overrides if compile time definition given.
|
||||
#if defined(TARGET_HOST_MZ700)
|
||||
#define TARGET_HOST_MZ700 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ2000)
|
||||
#define TARGET_HOST_MZ2000 1
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ80A)
|
||||
#define TARGET_HOST_MZ80A 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_PCW8XXX) || defined(TARGET_HOST_PCW9XXX)
|
||||
#define TARGET_HOST_PCW 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#else
|
||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||
#endif
|
||||
|
||||
// Video display constants.
|
||||
#define VC_MAX_ROWS 25 // Maximum number of rows on display.
|
||||
#define VC_MAX_COLUMNS 80 // Maximum number of columns on display.
|
||||
#define VC_MAX_BUFFER_ROWS 50 // Maximum number of backing store rows for scrollback feature.
|
||||
#define VC_DISPLAY_BUFFER_SIZE VC_MAX_COLUMNS * VC_MAX_BUFFER_ROWS // Size of the display buffer for scrollback.
|
||||
#define VC_MAX_ROWS 25 // Maximum number of rows on display.
|
||||
#if defined(TARGET_HOST_MZ700)
|
||||
#define VC_MAX_COLUMNS 40 // Maximum number of columns on display.
|
||||
#else
|
||||
#define VC_MAX_COLUMNS 80 // Maximum number of columns on display.
|
||||
#endif
|
||||
#define VC_MAX_BUFFER_ROWS 50 // Maximum number of backing store rows for scrollback feature.
|
||||
#define VC_DISPLAY_BUFFER_SIZE VC_MAX_COLUMNS * VC_MAX_BUFFER_ROWS // Size of the display buffer for scrollback.
|
||||
|
||||
// Keyboard constants.
|
||||
#define KEYB_AUTOREPEAT_INITIAL_TIME 800 // Time in milliseconds before starting autorepeat.
|
||||
#define KEYB_AUTOREPEAT_TIME 100 // Time in milliseconds between auto repeating characters.
|
||||
#define KEYB_FLASH_TIME 350 // Time in milliseconds for the cursor flash change.
|
||||
#define CURSOR_THICK_BLOCK 0x43 // Thick block cursor for lower case CAPS OFF
|
||||
#define CURSOR_BLOCK 0xEF // Block cursor for SHIFT Lock.
|
||||
#define CURSOR_UNDERLINE 0x3E // Thick underscore for CAPS Lock.
|
||||
#define MAX_KEYB_BUFFER_SIZE 32 // Maximum size of the keyboard buffer.
|
||||
#define KEYB_AUTOREPEAT_INITIAL_TIME 800 // Time in milliseconds before starting autorepeat.
|
||||
#define KEYB_AUTOREPEAT_TIME 100 // Time in milliseconds between auto repeating characters.
|
||||
#define KEYB_FLASH_TIME 350 // Time in milliseconds for the cursor flash change.
|
||||
#define CURSOR_THICK_BLOCK 0x43 // Thick block cursor for lower case CAPS OFF
|
||||
#define CURSOR_BLOCK 0xEF // Block cursor for SHIFT Lock.
|
||||
#define CURSOR_UNDERLINE 0x3E // Thick underscore for CAPS Lock.
|
||||
#define MAX_KEYB_BUFFER_SIZE 32 // Maximum size of the keyboard buffer.
|
||||
|
||||
// Audio constants.
|
||||
#define TIMER_8253_MZ80A_FREQ 2000000 // Base input frequency of Timer 0 for square wave generation.
|
||||
#define TIMER_8253_MZ700 768000 // Base input frequency of Timer 0 for square wave generation.
|
||||
#define TIMER_8253_MZ80A_FREQ 2000000 // Base input frequency of Timer 0 for square wave generation.
|
||||
#define TIMER_8253_MZ700_FREQ 768000 // Base input frequency of Timer 0 for square wave generation.
|
||||
|
||||
// Base addresses and sizes within the Video Controller.
|
||||
#define VIDEO_BASE_ADDR 0x000000 // Base address of the Video Controller.
|
||||
#define VIDEO_VRAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D000 // Base address of the character video RAM using direct addressing.
|
||||
#define VIDEO_VRAM_SIZE 0x800 // Size of the video RAM.
|
||||
#define VIDEO_ARAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D800 // Base address of the character attribute RAM using direct addressing.
|
||||
#define VIDEO_ARAM_SIZE 0x800 // Size of the attribute RAM.
|
||||
#define VIDEO_BASE_ADDR 0x000000 // Base address of the Video Controller.
|
||||
#define VIDEO_VRAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D000 // Base address of the character video RAM using direct addressing.
|
||||
#define VIDEO_VRAM_SIZE 0x800 // Size of the video RAM.
|
||||
#define VIDEO_ARAM_BASE_ADDR VIDEO_BASE_ADDR + 0x00D800 // Base address of the character attribute RAM using direct addressing.
|
||||
#define VIDEO_ARAM_SIZE 0x800 // Size of the attribute RAM.
|
||||
|
||||
// Video Module control bits.
|
||||
#define VMMODE_MASK 0xF8 // Mask to mask out video mode.
|
||||
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
||||
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
||||
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
||||
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
||||
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
||||
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
||||
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
||||
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
||||
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
||||
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
||||
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
||||
#define VMMODE_80CHAR 0x80 // Enable 80 character display.
|
||||
#define VMMODE_80CHAR_MASK 0x7F // Mask to filter out display width control bit.
|
||||
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
||||
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
||||
#define VMMODE_MASK 0xF8 // Mask to mask out video mode.
|
||||
#define VMMODE_MZ80K 0x00 // Video mode = MZ80K
|
||||
#define VMMODE_MZ80C 0x01 // Video mode = MZ80C
|
||||
#define VMMODE_MZ1200 0x02 // Video mode = MZ1200
|
||||
#define VMMODE_MZ80A 0x03 // Video mode = MZ80A
|
||||
#define VMMODE_MZ700 0x04 // Video mode = MZ700
|
||||
#define VMMODE_MZ800 0x05 // Video mode = MZ800
|
||||
#define VMMODE_MZ1500 0x06 // Video mode = MZ1500
|
||||
#define VMMODE_MZ80B 0x07 // Video mode = MZ80B
|
||||
#define VMMODE_MZ2000 0x08 // Video mode = MZ2000
|
||||
#define VMMODE_MZ2200 0x09 // Video mode = MZ2200
|
||||
#define VMMODE_MZ2500 0x0A // Video mode = MZ2500
|
||||
#define VMMODE_80CHAR 0x80 // Enable 80 character display.
|
||||
#define VMMODE_80CHAR_MASK 0x7F // Mask to filter out display width control bit.
|
||||
#define VMMODE_COLOUR 0x20 // Enable colour display.
|
||||
#define VMMODE_COLOUR_MASK 0xDF // Mask to filter out colour control bit.
|
||||
|
||||
// Sharp MZ colour attributes.
|
||||
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
||||
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
||||
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
||||
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
||||
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
||||
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
||||
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow character attribute.
|
||||
#define VMATTR_FG_WHITE 0x70 // Foreground white character attribute.
|
||||
#define VMATTR_FG_MASKOUT 0x8F // Mask to filter out foreground attribute.
|
||||
#define VMATTR_FG_MASKIN 0x70 // Mask to filter out foreground attribute.
|
||||
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
||||
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
||||
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
||||
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
||||
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
||||
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
||||
#define VMATTR_BG_YELLOW 0x06 // Background yellow character attribute.
|
||||
#define VMATTR_BG_WHITE 0x07 // Background white character attribute.
|
||||
#define VMATTR_BG_MASKOUT 0xF8 // Mask to filter out background attribute.
|
||||
#define VMATTR_BG_MASKIN 0x07 // Mask to filter out background attribute.
|
||||
#define VMATTR_FG_BLACK 0x00 // Foreground black character attribute.
|
||||
#define VMATTR_FG_BLUE 0x10 // Foreground blue character attribute.
|
||||
#define VMATTR_FG_RED 0x20 // Foreground red character attribute.
|
||||
#define VMATTR_FG_PURPLE 0x30 // Foreground purple character attribute.
|
||||
#define VMATTR_FG_GREEN 0x40 // Foreground green character attribute.
|
||||
#define VMATTR_FG_CYAN 0x50 // Foreground cyan character attribute.
|
||||
#define VMATTR_FG_YELLOW 0x60 // Foreground yellow character attribute.
|
||||
#define VMATTR_FG_WHITE 0x70 // Foreground white character attribute.
|
||||
#define VMATTR_FG_MASKOUT 0x8F // Mask to filter out foreground attribute.
|
||||
#define VMATTR_FG_MASKIN 0x70 // Mask to filter out foreground attribute.
|
||||
#define VMATTR_BG_BLACK 0x00 // Background black character attribute.
|
||||
#define VMATTR_BG_BLUE 0x01 // Background blue character attribute.
|
||||
#define VMATTR_BG_RED 0x02 // Background red character attribute.
|
||||
#define VMATTR_BG_PURPLE 0x03 // Background purple character attribute.
|
||||
#define VMATTR_BG_GREEN 0x04 // Background green character attribute.
|
||||
#define VMATTR_BG_CYAN 0x05 // Background cyan character attribute.
|
||||
#define VMATTR_BG_YELLOW 0x06 // Background yellow character attribute.
|
||||
#define VMATTR_BG_WHITE 0x07 // Background white character attribute.
|
||||
#define VMATTR_BG_MASKOUT 0xF8 // Mask to filter out background attribute.
|
||||
#define VMATTR_BG_MASKIN 0x07 // Mask to filter out background attribute.
|
||||
|
||||
// Sharp MZ constants.
|
||||
//
|
||||
#define MBADDR_KEYPA 0xE000 // Mainboard 8255 Port A
|
||||
#define MBADDR_KEYPB 0xE001 // Mainboard 8255 Port B
|
||||
#define MBADDR_KEYPC 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_KEYPF 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CSTR 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_CSTPT 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CONT0 0xE004 // Mainboard 8253 Counter 0
|
||||
#define MBADDR_CONT1 0xE005 // Mainboard 8253 Counter 1
|
||||
#define MBADDR_CONT2 0xE006 // Mainboard 8253 Counter 1
|
||||
#define MBADDR_CONTF 0xE007 // Mainboard 8253 Mode Control
|
||||
#define MBADDR_SUNDG 0xE008 // Register for reading the tempo timer status (cursor flash). horizontal blank and switching sound on/off.
|
||||
#define MBADDR_TEMP 0xE008 // As above, different name used in original source when writing.
|
||||
#define MBADDR_MEMSW 0xE00C // Memory swap, 0000->C000, C000->0000
|
||||
#define MBADDR_MEMSWR 0xE010 // Reset memory swap.
|
||||
#define MBADDR_NRMDSP 0xE014 // Return display to normal.
|
||||
#define MBADDR_INVDSP 0xE015 // Invert display.
|
||||
#define MBADDR_SCLDSP 0xE200 // Hardware scroll, a read to each location adds 8 to the start of the video access address therefore creating hardware scroll. 00 - reset to power up
|
||||
#define MBADDR_SCLBASE 0xE2 // High byte scroll base.
|
||||
#define MBADDR_DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||
#define MBADDR_KEYPA 0xE000 // Mainboard 8255 Port A
|
||||
#define MBADDR_KEYPB 0xE001 // Mainboard 8255 Port B
|
||||
#define MBADDR_KEYPC 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_KEYPF 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CSTR 0xE002 // Mainboard 8255 Port C
|
||||
#define MBADDR_CSTPT 0xE003 // Mainboard 8255 Mode Control
|
||||
#define MBADDR_CONT0 0xE004 // Mainboard 8253 Counter 0
|
||||
#define MBADDR_CONT1 0xE005 // Mainboard 8253 Counter 1
|
||||
#define MBADDR_CONT2 0xE006 // Mainboard 8253 Counter 1
|
||||
#define MBADDR_CONTF 0xE007 // Mainboard 8253 Mode Control
|
||||
#define MBADDR_SUNDG 0xE008 // Register for reading the tempo timer status (cursor flash). horizontal blank and switching sound on/off.
|
||||
#define MBADDR_TEMP 0xE008 // As above, different name used in original source when writing.
|
||||
#define MBADDR_MEMSW 0xE00C // Memory swap, 0000->C000, C000->0000
|
||||
#define MBADDR_MEMSWR 0xE010 // Reset memory swap.
|
||||
#define MBADDR_NRMDSP 0xE014 // Return display to normal.
|
||||
#define MBADDR_INVDSP 0xE015 // Invert display.
|
||||
#define MBADDR_SCLDSP 0xE200 // Hardware scroll, a read to each location adds 8 to the start of the video access address therefore creating hardware scroll. 00 - reset to power up
|
||||
#define MBADDR_SCLBASE 0xE2 // High byte scroll base.
|
||||
#define MBADDR_DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||
|
||||
//Common character definitions.
|
||||
#define SCROLL 0x01 // Set scroll direction UP.
|
||||
#define BELL 0x07
|
||||
#define ENQ 0x05
|
||||
#define SPACE 0x20
|
||||
#define TAB 0x09 // TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
#define CR 0x0D
|
||||
#define LF 0x0A
|
||||
#define FF 0x0C
|
||||
#define DELETE 0x7F
|
||||
#define BACKS 0x08
|
||||
#define SOH 0x01 // For XModem etc.
|
||||
#define EOT 0x04
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define NUL 0x00
|
||||
//#define NULL 0x00
|
||||
#define CTRL_A 0x01
|
||||
#define CTRL_B 0x02
|
||||
#define CTRL_C 0x03
|
||||
#define CTRL_D 0x04
|
||||
#define CTRL_E 0x05
|
||||
#define CTRL_F 0x06
|
||||
#define CTRL_G 0x07
|
||||
#define CTRL_H 0x08
|
||||
#define CTRL_I 0x09
|
||||
#define CTRL_J 0x0A
|
||||
#define CTRL_K 0x0B
|
||||
#define CTRL_L 0x0C
|
||||
#define CTRL_M 0x0D
|
||||
#define CTRL_N 0x0E
|
||||
#define CTRL_O 0x0F
|
||||
#define CTRL_P 0x10
|
||||
#define CTRL_Q 0x11
|
||||
#define CTRL_R 0x12
|
||||
#define CTRL_S 0x13
|
||||
#define CTRL_T 0x14
|
||||
#define CTRL_U 0x15
|
||||
#define CTRL_V 0x16
|
||||
#define CTRL_W 0x17
|
||||
#define CTRL_X 0x18
|
||||
#define CTRL_Y 0x19
|
||||
#define CTRL_Z 0x1A
|
||||
#define ESC 0x1B
|
||||
#define CTRL_SLASH 0x1C
|
||||
#define CTRL_LB 0x1B
|
||||
#define CTRL_RB 0x1D
|
||||
#define CTRL_CAPPA 0x1E
|
||||
#define CTRL_UNDSCR 0x1F
|
||||
#define CTRL_AT 0x00
|
||||
#define FUNC1 0x80
|
||||
#define FUNC2 0x81
|
||||
#define FUNC3 0x82
|
||||
#define FUNC4 0x83
|
||||
#define FUNC5 0x84
|
||||
#define FUNC6 0x85
|
||||
#define FUNC7 0x86
|
||||
#define FUNC8 0x87
|
||||
#define FUNC9 0x88
|
||||
#define FUNC10 0x89
|
||||
#define PAGEUP 0xE0
|
||||
#define PAGEDOWN 0xE1
|
||||
#define CURHOMEKEY 0xE2
|
||||
#define ALPHAGRAPHKEY 0xE3
|
||||
#define HOTKEY_ORIGINAL 0xE8
|
||||
#define HOTKEY_RFS80 0xE9
|
||||
#define HOTKEY_RFS40 0xEA
|
||||
#define HOTKEY_TZFS 0xEB
|
||||
#define HOTKEY_LINUX 0xEC
|
||||
#define NOKEY 0xF0
|
||||
#define CURSRIGHT 0xF1
|
||||
#define CURSLEFT 0xF2
|
||||
#define CURSUP 0xF3
|
||||
#define CURSDOWN 0xF4
|
||||
#define DBLZERO 0xF5
|
||||
#define INSERT 0xF6
|
||||
#define CLRKEY 0xF7
|
||||
#define HOMEKEY 0xF8
|
||||
#define ENDKEY 0xF9
|
||||
#define ANSITGLKEY 0xFA
|
||||
#define BREAKKEY 0xFB
|
||||
#define GRAPHKEY 0xFC
|
||||
#define ALPHAKEY 0xFD
|
||||
#define DEBUGKEY 0xFE // Special key to enable debug features such as the ANSI emulation.
|
||||
#define SCROLL 0x01 // Set scroll direction UP.
|
||||
#define BELL 0x07
|
||||
#define ENQ 0x05
|
||||
#define SPACE 0x20
|
||||
#define TAB 0x09 // TAB ACROSS (8 SPACES FOR SD-BOARD)
|
||||
#define CR 0x0D
|
||||
#define LF 0x0A
|
||||
#define FF 0x0C
|
||||
#define DELETE 0x7F
|
||||
#define BACKS 0x08
|
||||
#define SOH 0x01 // For XModem etc.
|
||||
#define EOT 0x04
|
||||
#define ACK 0x06
|
||||
#define NAK 0x15
|
||||
#define NUL 0x00
|
||||
//#define NULL 0x00
|
||||
#define CTRL_A 0x01
|
||||
#define CTRL_B 0x02
|
||||
#define CTRL_C 0x03
|
||||
#define CTRL_D 0x04
|
||||
#define CTRL_E 0x05
|
||||
#define CTRL_F 0x06
|
||||
#define CTRL_G 0x07
|
||||
#define CTRL_H 0x08
|
||||
#define CTRL_I 0x09
|
||||
#define CTRL_J 0x0A
|
||||
#define CTRL_K 0x0B
|
||||
#define CTRL_L 0x0C
|
||||
#define CTRL_M 0x0D
|
||||
#define CTRL_N 0x0E
|
||||
#define CTRL_O 0x0F
|
||||
#define CTRL_P 0x10
|
||||
#define CTRL_Q 0x11
|
||||
#define CTRL_R 0x12
|
||||
#define CTRL_S 0x13
|
||||
#define CTRL_T 0x14
|
||||
#define CTRL_U 0x15
|
||||
#define CTRL_V 0x16
|
||||
#define CTRL_W 0x17
|
||||
#define CTRL_X 0x18
|
||||
#define CTRL_Y 0x19
|
||||
#define CTRL_Z 0x1A
|
||||
#define ESC 0x1B
|
||||
#define CTRL_SLASH 0x1C
|
||||
#define CTRL_LB 0x1B
|
||||
#define CTRL_RB 0x1D
|
||||
#define CTRL_CAPPA 0x1E
|
||||
#define CTRL_UNDSCR 0x1F
|
||||
#define CTRL_AT 0x00
|
||||
#define FUNC1 0x80
|
||||
#define FUNC2 0x81
|
||||
#define FUNC3 0x82
|
||||
#define FUNC4 0x83
|
||||
#define FUNC5 0x84
|
||||
#define FUNC6 0x85
|
||||
#define FUNC7 0x86
|
||||
#define FUNC8 0x87
|
||||
#define FUNC9 0x88
|
||||
#define FUNC10 0x89
|
||||
#define PAGEUP 0xE0
|
||||
#define PAGEDOWN 0xE1
|
||||
#define CURHOMEKEY 0xE2
|
||||
#define ALPHAGRAPHKEY 0xE3
|
||||
#define HOTKEY_ORIGINAL 0xE8
|
||||
#define HOTKEY_RFS80 0xE9
|
||||
#define HOTKEY_RFS40 0xEA
|
||||
#define HOTKEY_TZFS 0xEB
|
||||
#define HOTKEY_LINUX 0xEC
|
||||
#define NOKEY 0xF0
|
||||
#define CURSRIGHT 0xF1
|
||||
#define CURSLEFT 0xF2
|
||||
#define CURSUP 0xF3
|
||||
#define CURSDOWN 0xF4
|
||||
#define DBLZERO 0xF5
|
||||
#define INSERT 0xF6
|
||||
#define CLRKEY 0xF7
|
||||
#define HOMEKEY 0xF8
|
||||
#define ENDKEY 0xF9
|
||||
#define ANSITGLKEY 0xFA
|
||||
#define BREAKKEY 0xFB
|
||||
#define GRAPHKEY 0xFC
|
||||
#define ALPHAKEY 0xFD
|
||||
#define DEBUGKEY 0xFE // Special key to enable debug features such as the ANSI emulation.
|
||||
|
||||
// Macros.
|
||||
//
|
||||
@@ -285,7 +313,7 @@ typedef struct {
|
||||
uint8_t dispCode;
|
||||
} t_dispCodeMap;
|
||||
|
||||
// Mapping table from keyboard scan codes to Sharp MZ-700 keys.
|
||||
// Mapping table from keyboard scan codes to Sharp MZ keys.
|
||||
//
|
||||
typedef struct {
|
||||
uint8_t scanCode[80];
|
||||
|
||||
@@ -431,7 +431,7 @@ uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
#ifdef INCLUDE_TEST_METHODS
|
||||
#if defined(INCLUDE_TEST_METHODS) && INCLUDE_TEST_METHODS == 1
|
||||
#include "z80io_test.c"
|
||||
#else
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
|
||||
95
software/FusionX/src/ttymz/z80io.h
vendored
95
software/FusionX/src/ttymz/z80io.h
vendored
@@ -39,7 +39,7 @@
|
||||
#endif
|
||||
|
||||
// Definitions to control compilation.
|
||||
//#define INCLUDE_TEST_METHODS 0
|
||||
#define INCLUDE_TEST_METHODS 0
|
||||
|
||||
// CPLD Commands.
|
||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
||||
@@ -82,6 +82,14 @@
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR 0x38
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P1 0x39
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P2 0x3A
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P3 0x3B
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P4 0x3C
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P5 0x3D
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P6 0x3E
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P7 0x3F
|
||||
#define CPLD_CMD_HALT 0x50
|
||||
#define CPLD_CMD_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
@@ -386,8 +394,8 @@
|
||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
||||
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
#define SPI_SEND_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
@@ -396,9 +404,18 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND_I_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
@@ -406,10 +423,9 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
@@ -417,24 +433,63 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32i(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
pr_info("Stage 0");\
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
pr_info("Stage 1");\
|
||||
#define SPI_SEND_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) != 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
pr_info("Stage 2");\
|
||||
timeout = MAX_CHECK_CNT; \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; }; \
|
||||
pr_info("Stage 3");\
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SET_FRAME_SIZE() { MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
}
|
||||
#define SPI_SEND_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
}
|
||||
#define SPI_SEND_I_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND_48(_d1_, _d2_, _d3_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 6); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d3_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+2, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
// write 2 byte
|
||||
|
||||
@@ -1,794 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80ctrl.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Control Interface
|
||||
// This file contains a command line utility tool for controlling the z80drv device
|
||||
// driver. The tool allows manipulation of the emulated Z80, inspection of its
|
||||
// memory and data, transmission of adhoc commands to the underlying CPLD-Z80
|
||||
// gateway and loading/saving of programs and data to/from the Z80 virtual and
|
||||
// host memory.
|
||||
//
|
||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
||||
// The Z80 CPU Emulator is the heart of the Z80 device driver.
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <Z/constants/pointer.h>
|
||||
#include <Z/macros/member.h>
|
||||
#include <Z/macros/array.h>
|
||||
#include <Z80.h>
|
||||
#include "z80driver.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
#define AUTHOR "P.D.Smart"
|
||||
#define COPYRIGHT "(c) 2018-22"
|
||||
|
||||
// Getopt_long is buggy so we use optparse.
|
||||
#define OPTPARSE_IMPLEMENTATION
|
||||
#define OPTPARSE_API static
|
||||
#include "optparse.h"
|
||||
|
||||
// Device driver name.
|
||||
#define DEVICE_FILENAME "/dev/z80drv"
|
||||
|
||||
// Constants for the Sharp MZ80A MZF file format.
|
||||
#define MZF_HEADER_SIZE 128 // Size of the MZF header.
|
||||
#define MZF_ATTRIBUTE 0x00 // Code Type, 01 = Machine Code.
|
||||
#define MZF_FILENAME 0x01 // Title/Name (17 bytes).
|
||||
#define MZF_FILENAME_LEN 17 // Length of the filename, it is not NULL terminated, generally a CR can be taken as terminator but not guaranteed.
|
||||
#define MZF_FILESIZE 0x12 // Size of program.
|
||||
#define MZF_LOADADDR 0x14 // Load address of program.
|
||||
#define MZF_EXECADDR 0x16 // Exec address of program.
|
||||
#define MZF_COMMENT 0x18 // Comment, used for details of the file or startup code.
|
||||
#define MZF_COMMENT_LEN 104 // Length of the comment field.
|
||||
#define CMT_TYPE_OBJCD 0x001 // MZF contains a binary object.
|
||||
#define CMT_TYPE_BTX1CD 0x002 // MZF contains a BASIC program.
|
||||
#define CMT_TYPE_BTX2CD 0x005 // MZF contains a BASIC program.
|
||||
#define CMT_TYPE_TZOBJCD0 0x0F8 // MZF contains a TZFS binary object for page 0.
|
||||
#define CMT_TYPE_TZOBJCD1 0x0F9
|
||||
#define CMT_TYPE_TZOBJCD2 0x0FA
|
||||
#define CMT_TYPE_TZOBJCD3 0x0FB
|
||||
#define CMT_TYPE_TZOBJCD4 0x0FC
|
||||
#define CMT_TYPE_TZOBJCD5 0x0FD
|
||||
#define CMT_TYPE_TZOBJCD6 0x0FE
|
||||
#define CMT_TYPE_TZOBJCD7 0x0FF // MZF contains a TZFS binary object for page 7.
|
||||
#define MZ_CMT_ADDR 0x10F0
|
||||
|
||||
// Structure to define a Sharp MZ80A MZF directory structure. This header appears at the beginning of every Sharp MZ80A tape (and more recently archived/emulator) images.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t attr; // MZF attribute describing the file.
|
||||
uint8_t fileName[MZF_FILENAME_LEN]; // Each directory entry is the size of an MZF filename.
|
||||
uint16_t fileSize; // Size of file.
|
||||
uint16_t loadAddr; // Load address for the file.
|
||||
uint16_t execAddr; // Execution address where the Z80 starts processing.
|
||||
uint8_t comment[MZF_COMMENT_LEN]; // Text comment field but often contains a startup machine code program.
|
||||
} t_svcDirEnt;
|
||||
|
||||
// Possible commands to be issued to the Z80 driver.
|
||||
enum CTRL_COMMANDS {
|
||||
Z80_CMD_STOP = 0,
|
||||
Z80_CMD_START = 1,
|
||||
Z80_CMD_PAUSE = 2,
|
||||
Z80_CMD_CONTINUE = 3,
|
||||
Z80_CMD_RESET = 4,
|
||||
Z80_CMD_SPEED = 5,
|
||||
Z80_CMD_HOST_RAM = 6,
|
||||
Z80_CMD_VIRTUAL_RAM = 7,
|
||||
Z80_CMD_DUMP_MEMORY = 8,
|
||||
Z80_CMD_MEMORY_TEST = 9,
|
||||
CPLD_CMD_SEND_CMD = 10,
|
||||
CPLD_CMD_SPI_TEST = 11,
|
||||
CPLD_CMD_PRL_TEST = 12
|
||||
};
|
||||
|
||||
|
||||
// Shared memory between this process and the Z80 driver.
|
||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
|
||||
// Method to obtain and return the output screen width.
|
||||
//
|
||||
uint8_t getScreenWidth(void)
|
||||
{
|
||||
return(MAX_SCREEN_WIDTH);
|
||||
}
|
||||
|
||||
struct termios orig_termios;
|
||||
|
||||
void reset_terminal_mode()
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &orig_termios);
|
||||
}
|
||||
|
||||
void set_conio_terminal_mode()
|
||||
{
|
||||
struct termios new_termios;
|
||||
|
||||
/* take two copies - one for now, one for later */
|
||||
tcgetattr(0, &orig_termios);
|
||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||
|
||||
/* register cleanup handler, and set the new terminal mode */
|
||||
atexit(reset_terminal_mode);
|
||||
cfmakeraw(&new_termios);
|
||||
tcsetattr(0, TCSANOW, &new_termios);
|
||||
}
|
||||
|
||||
int kbhit()
|
||||
{
|
||||
struct timeval tv = { 0L, 0L };
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
return select(1, &fds, NULL, NULL, &tv) > 0;
|
||||
}
|
||||
|
||||
int getch(uint8_t wait)
|
||||
{
|
||||
int r;
|
||||
unsigned char c;
|
||||
|
||||
if(wait != 0 || (wait == 0 && kbhit()))
|
||||
{
|
||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||
return r;
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void delay(int number_of_seconds)
|
||||
{
|
||||
// Converting time into milli_seconds
|
||||
int milli_seconds = 1000 * number_of_seconds;
|
||||
|
||||
// Storing start time
|
||||
clock_t start_time = clock();
|
||||
|
||||
// looping till required time is not achieved
|
||||
while (clock() < start_time + milli_seconds);
|
||||
}
|
||||
|
||||
// Function to dump out a given section of memory via the UART.
|
||||
//
|
||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth)
|
||||
{
|
||||
uint8_t displayWidth = dispwidth;;
|
||||
uint32_t pnt = memaddr;
|
||||
uint32_t endAddr = memaddr + memsize;
|
||||
uint32_t addr = dispaddr;
|
||||
uint32_t i = 0;
|
||||
//uint32_t data;
|
||||
int8_t keyIn;
|
||||
int result = -1;
|
||||
char c = 0;
|
||||
|
||||
// Sanity check. memoryFlag == 0 required kernel driver to dump so we exit as it cannot be performed here.
|
||||
if(memoryFlag == 0)
|
||||
return(-1);
|
||||
|
||||
// Reconfigure terminal to allow non-blocking key input.
|
||||
//
|
||||
set_conio_terminal_mode();
|
||||
|
||||
// If not set, calculate output line width according to connected display width.
|
||||
//
|
||||
if(displayWidth == 0)
|
||||
{
|
||||
switch(getScreenWidth())
|
||||
{
|
||||
case 40:
|
||||
displayWidth = 8;
|
||||
break;
|
||||
case 80:
|
||||
displayWidth = 16;
|
||||
break;
|
||||
default:
|
||||
displayWidth = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("%08lX", addr); // print address
|
||||
printf(": ");
|
||||
|
||||
// print hexadecimal data
|
||||
for (i=0; i < displayWidth; )
|
||||
{
|
||||
switch(memwidth)
|
||||
{
|
||||
case 16:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%04X", memoryFlag == 1 ? (uint16_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint16_t)Z80Ctrl->page[pnt+i] : (uint16_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%08lX", memoryFlag == 1 ? (uint32_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint32_t)Z80Ctrl->page[pnt+i] : (uint32_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
default:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%02X", memoryFlag == 1 ? (uint8_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint8_t)Z80Ctrl->page[pnt+i] : (uint8_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
fputc((char)' ', stdout);
|
||||
}
|
||||
|
||||
// print ascii data
|
||||
printf(" |");
|
||||
|
||||
// print single ascii char
|
||||
for (i=0; i < displayWidth; i++)
|
||||
{
|
||||
c = memoryFlag == 1 ? (char)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (char)Z80Ctrl->page[pnt+i] : (char)Z80Ctrl->iopage[pnt+i];
|
||||
if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~'))
|
||||
fputc((char)c, stdout);
|
||||
else
|
||||
fputc((char)' ', stdout);
|
||||
}
|
||||
|
||||
printf("|\r\n");
|
||||
fflush(stdout);
|
||||
|
||||
// Move on one row.
|
||||
pnt += displayWidth;
|
||||
addr += displayWidth;
|
||||
|
||||
// User abort (ESC), pause (Space) or all done?
|
||||
//
|
||||
keyIn = getch(0);
|
||||
if(keyIn == ' ')
|
||||
{
|
||||
do {
|
||||
keyIn = getch(0);
|
||||
} while(keyIn != ' ' && keyIn != 0x1b);
|
||||
}
|
||||
// Escape key pressed, exit with 0 to indicate this to caller.
|
||||
if (keyIn == 0x1b)
|
||||
{
|
||||
sleep(1);
|
||||
result = 0;
|
||||
goto memoryDumpExit;
|
||||
}
|
||||
|
||||
// End of buffer, exit the loop.
|
||||
if(pnt >= (memaddr + memsize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal exit, return -1 to show no key pressed.
|
||||
memoryDumpExit:
|
||||
reset_terminal_mode();
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Method to load a program or data file into the Z80 memory. First load into Virtual memory and then trigger a sync to bring Host RAM in line.
|
||||
//
|
||||
int z80load(int fdZ80, char *fileName)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
t_svcDirEnt mzfHeader;
|
||||
|
||||
// Pause the Z80.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Open the file and read directly into the Virtual memory via the share.
|
||||
FILE *ptr;
|
||||
ptr = fopen(fileName, "rb");
|
||||
if(ptr)
|
||||
{
|
||||
// First the header.
|
||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
||||
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
if(mzfHeader.loadAddr > 0x1000)
|
||||
{
|
||||
#endif
|
||||
// Copy in the header.
|
||||
memcpy((uint8_t *)&Z80Ctrl->memory[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
||||
|
||||
// Now read in the data.
|
||||
fread(&Z80Ctrl->memory[mzfHeader.loadAddr], mzfHeader.fileSize, 1, ptr);
|
||||
printf("Loaded %s, Size:%04x, Addr:%04x, Exec:%04x\n", fileName, mzfHeader.fileSize, mzfHeader.loadAddr, mzfHeader.execAddr);
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
}
|
||||
#endif
|
||||
|
||||
// Sync the loaded image from Virtual memory to hard memory.
|
||||
ioctlCmd.cmd = IOCTL_CMD_SYNC_TO_HOST_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
// Set PC to 2 (NST) which switches to RUN mode and executes at 0000H
|
||||
ioctlCmd.z80.pc = 2;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
// MZ-700 just use the MZF header exec address.
|
||||
ioctlCmd.z80.pc = mzfHeader.execAddr;
|
||||
#endif
|
||||
|
||||
// Set PC to required setting ready for run.
|
||||
ioctlCmd.cmd = IOCTL_CMD_SETPC;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Resume Z80 processing.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
else
|
||||
printf("Couldnt open file\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Method to request basic Z80 operations.
|
||||
//
|
||||
int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long param3)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
uint32_t idx;
|
||||
int ret = 0;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case Z80_CMD_STOP:
|
||||
// Use IOCTL to request Z80 to Stop (power off) processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_START:
|
||||
// Use IOCTL to request Z80 to Start (power on) processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_PAUSE:
|
||||
// Use IOCTL to request Z80 to pause processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_CONTINUE:
|
||||
// Use IOCTL to request Z80 continue processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_RESET:
|
||||
// Use IOCTL to request Z80 reset.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_SPEED:
|
||||
// Check value is in range.
|
||||
for(idx=1; idx < 256; idx+=idx)
|
||||
{
|
||||
if((uint32_t)param1 == idx) break;
|
||||
}
|
||||
if(idx == 256)
|
||||
{
|
||||
printf("Speed factor is illegal. It must be a multiple value of the original CPU clock, ie. 1x, 2x, 4x etc\n");
|
||||
ret = -1;
|
||||
} else
|
||||
{
|
||||
// Use IOCTL to request Z80 cpu freq change.
|
||||
ioctlCmd.speed.speedMultiplier = (uint32_t)param1;
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CPU_FREQ;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case CPLD_CMD_SEND_CMD:
|
||||
// Build up the IOCTL command to request the given data is sent to the CPLD.
|
||||
ioctlCmd.cmd = IOCTL_CMD_CPLD_CMD;
|
||||
ioctlCmd.cpld.cmd = (uint32_t)param1;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_DUMP_MEMORY:
|
||||
// If virtual memory, we can dump it via the shared memory segment.
|
||||
if((uint8_t)param1)
|
||||
{
|
||||
memoryDump((uint32_t)param2, (uint32_t)param3, (uint8_t)param1, (uint8_t)param1 == 2 || (uint8_t)param1 == 3 ? 32 : 8, (uint32_t)param2, 0);
|
||||
} else
|
||||
{
|
||||
// Build an IOCTL command to get the driver to dump the memory.
|
||||
ioctlCmd.cmd = IOCTL_CMD_DUMP_MEMORY;
|
||||
ioctlCmd.addr.start = (uint32_t)param2;
|
||||
ioctlCmd.addr.end = (uint32_t)param2+(uint32_t)param3;
|
||||
ioctlCmd.addr.size = (uint32_t)param3;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case Z80_CMD_HOST_RAM:
|
||||
// Use IOCTL to request change to host RAM.
|
||||
ioctlCmd.cmd = IOCTL_CMD_USE_HOST_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_VIRTUAL_RAM:
|
||||
// Use IOCTL to request change to host RAM.
|
||||
ioctlCmd.cmd = IOCTL_CMD_USE_VIRTUAL_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_MEMORY_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_MEMTEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case CPLD_CMD_PRL_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_PRL_TEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case CPLD_CMD_SPI_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_SPI_TEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Command not supported!\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Method to perform some simple tests on the Z80 emulator.
|
||||
//
|
||||
int z80test(int fdZ80)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
|
||||
// Stop the Z80.
|
||||
//
|
||||
printf("Send STOP\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
FILE *ptr;
|
||||
ptr = fopen("/customer/mz700.rom", "rb");
|
||||
if(ptr)
|
||||
{
|
||||
fread(&Z80Ctrl->memory, 65536, 1, ptr);
|
||||
} else printf("Couldnt open file\n");
|
||||
|
||||
// Configure the Z80.
|
||||
//
|
||||
printf("Send SETPC\n");
|
||||
ioctlCmd.z80.pc = 0;
|
||||
ioctl(fdZ80, IOCTL_CMD_SETPC, &ioctlCmd);
|
||||
|
||||
memoryDump(0 , 65536, 1, 8, 0, 0);
|
||||
|
||||
// Start the Z80.
|
||||
//
|
||||
printf("Send START\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
delay(10);
|
||||
|
||||
printf("Send STOP\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
memoryDump(0, 65536, 1, 8, 0, 0);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Output usage screen. So mamy commands you do need to be prompted!!
|
||||
void showArgs(char *progName, struct optparse *options)
|
||||
{
|
||||
printf("%s %s %s %s\n\n", progName, VERSION, COPYRIGHT, AUTHOR);
|
||||
printf("Synopsis:\n");
|
||||
printf("%s --help # This help screen.\n", progName);
|
||||
printf(" --cmd <command> = RESET # Reset the Z80\n");
|
||||
printf(" = STOP # Stop and power off the Z80\n");
|
||||
printf(" = START # Power on and start the Z80\n");
|
||||
printf(" = PAUSE # Pause running Z80\n");
|
||||
printf(" = CONTINUE # Continue Z80 execution\n");
|
||||
printf(" = HOSTRAM # Use HOST DRAM\n");
|
||||
printf(" = VIRTRAM # Use Virtual RAM\n");
|
||||
printf(" = SPEED --speed <1, 2, 4, 8, 16, 32, 64, 128> # In Virtual RAM mode, set CPU speed to base clock x factor.\n");
|
||||
printf(" = LOADMZF --file <mzf filename> # Load MZF file into memory.\n");
|
||||
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>]--virtual <0 - Host RAM, 1 = Virtual RAM, 2 = PageTable, 3 = IOPageTable>\n");
|
||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
||||
printf(" = Z80TEST # Perform various debugging tests\n");
|
||||
printf(" = SPITEST # Perform SPI testing\n");
|
||||
printf(" = PRLTEST # Perform Parallel Bus testing\n");
|
||||
printf(" = Z80MEMTEST # Perform HOST memory tests.\n");
|
||||
printf(" --<cmd> # Some commands can be abbreviated.\n");
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fdZ80;
|
||||
char buff[64];
|
||||
char cmd[64] = { 0 };
|
||||
char fileName[256] = { 0 };
|
||||
int opt;
|
||||
uint32_t hexData = 0;
|
||||
long speedMultiplier = 1;
|
||||
long startAddr = 0x0000;
|
||||
long endAddr = 0x1000;
|
||||
int virtualMemory = 0;
|
||||
int helpFlag = 0;
|
||||
int verboseFlag = 0;
|
||||
|
||||
// Define parameters to be processed.
|
||||
struct optparse options;
|
||||
static struct optparse_long long_options[] =
|
||||
{
|
||||
{"help", 'h', OPTPARSE_NONE},
|
||||
{"cmd", 'c', OPTPARSE_REQUIRED},
|
||||
{"file", 'f', OPTPARSE_REQUIRED},
|
||||
{"data", 'd', OPTPARSE_REQUIRED},
|
||||
{"speed", 'S', OPTPARSE_REQUIRED},
|
||||
{"virtual", 'V', OPTPARSE_REQUIRED},
|
||||
{"addr", 'a', OPTPARSE_REQUIRED},
|
||||
{"end", 'e', OPTPARSE_REQUIRED},
|
||||
{"size", 's', OPTPARSE_REQUIRED},
|
||||
{"verbose", 'v', OPTPARSE_NONE},
|
||||
{"dump", '1', OPTPARSE_NONE},
|
||||
{"loadmzf", '2', OPTPARSE_NONE},
|
||||
{"reset", '3', OPTPARSE_NONE},
|
||||
{"stop", '4', OPTPARSE_NONE},
|
||||
{"start", '5', OPTPARSE_NONE},
|
||||
{"pause", '6', OPTPARSE_NONE},
|
||||
{"continue", '7', OPTPARSE_NONE},
|
||||
{"speed", '8', OPTPARSE_NONE},
|
||||
{"cpldcmd", '9', OPTPARSE_NONE},
|
||||
{0}
|
||||
};
|
||||
|
||||
// Parse the command line options.
|
||||
//
|
||||
optparse_init(&options, argv);
|
||||
while((opt = optparse_long(&options, long_options, NULL)) != -1)
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
// Hex data.
|
||||
case 'd':
|
||||
// hexData = (uint32_t)strtol(options.optarg, NULL, 0);
|
||||
sscanf(options.optarg, "0x%08x", &hexData);
|
||||
printf("Hex data:%08x\n", hexData);
|
||||
break;
|
||||
|
||||
// Start address for memory operations.
|
||||
case 'a':
|
||||
startAddr = strtol(options.optarg, NULL, 0);
|
||||
//printf("Start Addr:%04x\n", startAddr);
|
||||
break;
|
||||
|
||||
// Speed multiplication factor for CPU governor when running in virtual memory.
|
||||
case 'S':
|
||||
speedMultiplier = strtol(options.optarg, NULL, 0);
|
||||
//printf("Speed = base freq x %d\n", speedFactor);
|
||||
break;
|
||||
|
||||
// End address for memory operations.
|
||||
case 'e':
|
||||
endAddr = strtol(options.optarg, NULL, 0);
|
||||
//printf("End Addr:%04x\n", endAddr);
|
||||
break;
|
||||
|
||||
// Size instead of end address for memory operations.
|
||||
case 's':
|
||||
endAddr = startAddr + strtol(options.optarg, NULL, 0);
|
||||
//printf("End Addr:%04x\n", endAddr);
|
||||
break;
|
||||
|
||||
// Virtual memory flag, 0 = host, 1 = virtual memory, 2 = page table, 3 = iopage table.
|
||||
case 'V':
|
||||
virtualMemory = atoi(options.optarg);
|
||||
break;
|
||||
|
||||
// Filename.
|
||||
case 'f':
|
||||
strcpy(fileName, options.optarg);
|
||||
break;
|
||||
|
||||
// Command to execute.
|
||||
case 'c':
|
||||
strcpy(cmd, options.optarg);
|
||||
break;
|
||||
|
||||
// Quick command flags.
|
||||
case '1':
|
||||
strcpy(cmd, "DUMP");
|
||||
break;
|
||||
case '2':
|
||||
strcpy(cmd, "LOADMZF");
|
||||
break;
|
||||
case '3':
|
||||
strcpy(cmd, "RESET");
|
||||
break;
|
||||
case '4':
|
||||
strcpy(cmd, "STOP");
|
||||
break;
|
||||
case '5':
|
||||
strcpy(cmd, "START");
|
||||
break;
|
||||
case '6':
|
||||
strcpy(cmd, "PAUSE");
|
||||
break;
|
||||
case '7':
|
||||
strcpy(cmd, "CONTINUE");
|
||||
break;
|
||||
case '8':
|
||||
strcpy(cmd, "SPEED");
|
||||
break;
|
||||
case '9':
|
||||
strcpy(cmd, "CPLDCMD");
|
||||
break;
|
||||
|
||||
// Verbose mode.
|
||||
case 'v':
|
||||
verboseFlag = 1;
|
||||
break;
|
||||
|
||||
// Command help needed.
|
||||
case 'h':
|
||||
helpFlag = 1;
|
||||
showArgs(argv[0], &options);
|
||||
break;
|
||||
|
||||
// Unrecognised, show synopsis.
|
||||
case '?':
|
||||
showArgs(argv[0], &options);
|
||||
printf("%s: %s\n", argv[0], options.errmsg);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the z80drv driver and attach to its shared memory, basically the Z80 control structure which includes the virtual Z80 memory.
|
||||
fdZ80 = open(DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
||||
if(fdZ80 >= 0)
|
||||
{
|
||||
Z80Ctrl = (t_Z80Ctrl *)mmap(0, sizeof(t_Z80Ctrl), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
||||
if(Z80Ctrl == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exitting....\n");
|
||||
close(fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
{
|
||||
printf("Failed to open the Z80 Driver, exitting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Basic string to method mapping. Started off with just 1 or two but has grown, may need a table!
|
||||
if(strcasecmp(cmd, "LOADMZF") == 0)
|
||||
{
|
||||
z80load(fdZ80, fileName);
|
||||
} else
|
||||
if(strcasecmp(cmd, "RESET") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_RESET, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "STOP") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_STOP, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "START") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_START, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "PAUSE") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_PAUSE, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "CONTINUE") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_CONTINUE, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "SPEED") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_SPEED, speedMultiplier, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "DUMP") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, virtualMemory, startAddr, (endAddr - startAddr));
|
||||
} else
|
||||
if(strcasecmp(cmd, "HOSTRAM") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_HOST_RAM, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "VIRTRAM") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_VIRTUAL_RAM, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "CPLDCMD") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_SEND_CMD, hexData, 0, 0);
|
||||
} else
|
||||
|
||||
// Test methods, if the code is built-in to the driver.
|
||||
if(strcasecmp(cmd, "Z80TEST") == 0)
|
||||
{
|
||||
z80test(fdZ80);
|
||||
} else
|
||||
if(strcasecmp(cmd, "SPITEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_SPI_TEST, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "PRLTEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_PRL_TEST, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "Z80MEMTEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_MEMORY_TEST, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
showArgs(argv[0], &options);
|
||||
printf("No command given, nothing done!\n");
|
||||
}
|
||||
|
||||
// Unmap shared memory and close the device.
|
||||
munmap(Z80Ctrl, sizeof(t_Z80Ctrl));
|
||||
close(fdZ80);
|
||||
|
||||
return(0);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
326
software/FusionX/src/z80drv/MZ2000/z80driver.h
vendored
326
software/FusionX/src/z80drv/MZ2000/z80driver.h
vendored
@@ -1,326 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80driver.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Driver
|
||||
// This file contains the declarations used in the z80drv device driver.
|
||||
//
|
||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
||||
// The Z80 CPU Emulator is the heart of this driver and in all ways, is compatible with
|
||||
// the original Z80.
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80DRIVER_H
|
||||
#define Z80DRIVER_H
|
||||
|
||||
// Constants.
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ2000 1
|
||||
#define Z80_VIRTUAL_ROM_SIZE 16384 // Sized to maximum ROM which is the MZ-800 ROM.
|
||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 8) // (PAGE_SIZE * 2) // max size mmaped to userspace
|
||||
#define Z80_VIRTUAL_MEMORY_SIZE Z80_VIRTUAL_RAM_SIZE + Z80_VIRTUAL_ROM_SIZE
|
||||
#define Z80_MEMORY_PAGE_SIZE 16
|
||||
#define MAX_SCREEN_WIDTH 132
|
||||
#define DEVICE_NAME "z80drv"
|
||||
#define CLASS_NAME "mogu"
|
||||
|
||||
// Memory and IO page types. Used to create a memory page which maps type of address space to real address space on host or virtual memory.
|
||||
#define MEMORY_TYPE_VIRTUAL_MASK 0x00FFFFFF
|
||||
#define MEMORY_TYPE_REAL_MASK 0x0000FFFF
|
||||
#define IO_TYPE_MASK 0x0000FFFF
|
||||
#define MEMORY_TYPE_INHIBIT 0x00000000
|
||||
#define MEMORY_TYPE_PHYSICAL_RAM 0x80000000
|
||||
#define MEMORY_TYPE_PHYSICAL_ROM 0x40000000
|
||||
#define MEMORY_TYPE_PHYSICAL_VRAM 0x20000000
|
||||
#define MEMORY_TYPE_PHYSICAL_HW 0x10000000
|
||||
#define MEMORY_TYPE_VIRTUAL_RAM 0x08000000
|
||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
||||
#define MEMORY_TYPE_VIRTUAL_HW 0x02000000
|
||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
||||
|
||||
|
||||
// Approximate governor delays to regulate emulated CPU speed.
|
||||
// MZ-700
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||
#endif
|
||||
// MZ-2000
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 243
|
||||
#define INSTRUCTION_DELAY_ROM_7MHZ 122
|
||||
#define INSTRUCTION_DELAY_ROM_14MHZ 61
|
||||
#define INSTRUCTION_DELAY_ROM_28MHZ 30
|
||||
#define INSTRUCTION_DELAY_ROM_56MHZ 15
|
||||
#define INSTRUCTION_DELAY_ROM_112MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_224MHZ 3
|
||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 218
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 112
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 56
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 28
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 14
|
||||
#define INSTRUCTION_DELAY_RAM_112MHZ 7
|
||||
#define INSTRUCTION_DELAY_RAM_224MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||
#endif
|
||||
|
||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||
#define IOCTL_CMD_Z80_STOP 's'
|
||||
#define IOCTL_CMD_Z80_START 'S'
|
||||
#define IOCTL_CMD_Z80_PAUSE 'P'
|
||||
#define IOCTL_CMD_Z80_RESET 'R'
|
||||
#define IOCTL_CMD_Z80_CONTINUE 'C'
|
||||
#define IOCTL_CMD_USE_HOST_RAM 'x'
|
||||
#define IOCTL_CMD_USE_VIRTUAL_RAM 'X'
|
||||
#define IOCTL_CMD_DUMP_MEMORY 'M'
|
||||
#define IOCTL_CMD_Z80_CPU_FREQ 'F'
|
||||
#define IOCTL_CMD_CPLD_CMD 'z'
|
||||
#define IOCTL_CMD_SEND _IOW('c', 'c', int32_t *)
|
||||
#define IOCTL_CMD_SETPC _IOW('p', 'p', int32_t *)
|
||||
#define IOCTL_CMD_SYNC_TO_HOST_RAM 'V'
|
||||
#define IOCTL_CMD_SPI_TEST '1'
|
||||
#define IOCTL_CMD_PRL_TEST '2'
|
||||
#define IOCTL_CMD_Z80_MEMTEST '3'
|
||||
|
||||
|
||||
|
||||
// Chip Select map MZ80K-MZ700.
|
||||
//
|
||||
// 0000 - 0FFF = CS_ROMni : R/W : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||
// 1000 - CFFF = CS_RAMni : R/W : MZ80K/A/700 = RAM
|
||||
// C000 - CFFF = CS_ROMni : R/W : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||
// D000 - D7FF = CS_VRAMni : R/W : MZ80K/A/700 = VRAM
|
||||
// D800 - DFFF = CS_VRAMni : R/W : MZ700 = Colour VRAM (MZ700)
|
||||
// E000 - E003 = CS_8255n : R/W : MZ80K/A/700 = 8255
|
||||
// E004 - E007 = CS_8254n : R/W : MZ80K/A/700 = 8254
|
||||
// E008 - E00B = CS_LS367n : R/W : MZ80K/A/700 = LS367
|
||||
// E00C - E00F = CS_ESWPn : R : MZ80A = Memory Swap (MZ80A)
|
||||
// E010 - E013 = CS_ESWPn : R : MZ80A = Reset Memory Swap (MZ80A)
|
||||
// E014 = CS_E5n : R/W : MZ80A/700 = Normal CRT display (in Video Controller)
|
||||
// E015 = CS_E6n : R/W : MZ80A/700 = Reverse CRT display (in Video Controller)
|
||||
// E200 - E2FF = : R/W : MZ80A/700 = VRAM roll up/roll down.
|
||||
// E800 - EFFF = : R/W : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||
// F000 - F7FF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
||||
// F800 - FFFF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
||||
//
|
||||
// Chip Select map MZ800
|
||||
//
|
||||
// FC - FF = CS_PIOn : R/W : MZ800/MZ1500 = Z80 PIO Printer Interface
|
||||
// F2 = CS_PSG0n : W : MZ800/MZ1500 = Programable Sound Generator, MZ-800 = Mono, MZ-1500 = Left Channel
|
||||
// F3 = CS_PSG1n : W : MZ1500 = Programable Sound Generator, MZ-1500 = Right Channel
|
||||
// E9 = CS_PSG(X)n: W : MZ1500 = Simultaneous write to both PSG's.
|
||||
// F0 - F1 = CS_JOYSTK : R : MZ800 = Joystick 1 and 2
|
||||
// CC = CS_GWF : W : MZ800 = CRTC GWF Write format Register
|
||||
// CD = CS_GRF : W : MZ800 = CRTC GRF Read format Register
|
||||
// CE = CS_GDMD : W : MZ800 = CRTC GDMD Mode Register
|
||||
// CF = CS_GCRTC : W : MZ800 = CRTC GCRTC Control Register
|
||||
// D4 - D7 = CS
|
||||
// D000 - DFFF
|
||||
|
||||
// MZ700/MZ800 memory mode switch?
|
||||
//
|
||||
// MZ-700 MZ-800
|
||||
// |0000:0FFF|1000:1FFF|1000:CFFF|C000:CFFF|D000:FFFF |0000:7FFF|1000:1FFF|2000:7FFF|8000:BFFF|C000:CFFF|C000:DFFF|E000:FFFF
|
||||
// -------------------------------------------------- ----------------------------------------------------------------------
|
||||
// OUT 0xE0 = |DRAM | | | | |DRAM | | | | | |
|
||||
// OUT 0xE1 = | | | | |DRAM | | | | | | |DRAM
|
||||
// OUT 0xE2 = |MONITOR | | | | |MONITOR | | | | | |
|
||||
// OUT 0xE3 = | | | | |Memory Mapped I/O | | | | | | |Upper MONITOR ROM
|
||||
// OUT 0xE4 = |MONITOR | |DRAM | |Memory Mapped I/O |MONITOR |CGROM |DRAM |VRAM | |DRAM |Upper MONITOR ROM
|
||||
// OUT 0xE5 = | | | | |Inhibit | | | | | | |Inhibit
|
||||
// OUT 0xE6 = | | | | |<return> | | | | | | |<return>
|
||||
// IN 0xE0 = | |CGROM* | |VRAM* | | |CGROM | |VRAM | | |
|
||||
// IN 0xE1 = | |DRAM | |DRAM | | |<return> | |DRAM | | |
|
||||
//
|
||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||
// * = MZ-800 host only.
|
||||
|
||||
// Macros to lookup and test to see if a given memory block or IO byte is of a given type. Also macros to read/write to the memory block and IO byte.
|
||||
#define MEMORY_BLOCK_GRANULARITY 0x800
|
||||
#define MEMORY_BLOCK_SLOTS (0x10000 / MEMORY_BLOCK_GRANULARITY)
|
||||
#define MEMORY_BLOCK_MASK (0x10000 - MEMORY_BLOCK_GRANULARITY)
|
||||
#define MEMORY_BLOCK_SHIFT 11
|
||||
#define getPageData(a) (Z80Ctrl->page[(a & 0xF800) >> MEMORY_BLOCK_SHIFT])
|
||||
#define getIOPageData(a) (Z80Ctrl->iopage[(a & 0xFFFF])
|
||||
#define getPageType(a, mask) (getPageData(a) & mask)
|
||||
#define getPageAddr(a, mask) ((getPageData(a) & mask) + (a & (MEMORY_BLOCK_GRANULARITY-1)))
|
||||
#define getIOPageType(a, mask) (getIOPageData(a) & mask)
|
||||
#define getIOPageAddr(a, mask) (getIOPageData(a) & mask)
|
||||
#define realAddress(a) (Z80Ctrl->page[getPageAddr(a, MEMORY_TYPE_REAL_MASK)])
|
||||
#define realPort(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_MASK)
|
||||
#define isPhysicalRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_RAM))
|
||||
#define isPhysicalVRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_VRAM))
|
||||
#define isPhysicalROM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_ROM))
|
||||
#define isPhysicalMemory(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM))])
|
||||
#define isPhysicalHW(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_HW))
|
||||
#define isPhysical(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM)))
|
||||
#define isPhysicalIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_PHYSICAL_HW)
|
||||
#define isVirtualRAM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_RAM))
|
||||
#define isVirtualROM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_ROM))
|
||||
#define isVirtualMemory(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_RAM)))
|
||||
#define isVirtualHW(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_HW))
|
||||
#define isVirtualIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_VIRTUAL_HW)
|
||||
#define isHW(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_VIRTUAL_HW)))
|
||||
#define readVirtualRAM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
||||
#define readVirtualROM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) + Z80_VIRTUAL_RAM_SIZE ])
|
||||
#define writeVirtualRAM(a, d) { Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
||||
#define setMemoryType(_block_,_type_,_addr_) { Z80Ctrl->page[_block_] = _type_ | _addr_; }
|
||||
#define backupMemoryType(_block_) { Z80Ctrl->shadowPage[_block_] = Z80Ctrl->page[_block_]; }
|
||||
#define restoreMemoryType(_block_) { Z80Ctrl->page[_block_] = Z80Ctrl->shadowPage[_block_]; }
|
||||
|
||||
#define IO_ADDR_E0 0xE0
|
||||
#define IO_ADDR_E1 0xE1
|
||||
#define IO_ADDR_E2 0xE2
|
||||
#define IO_ADDR_E3 0xE3
|
||||
#define IO_ADDR_E4 0xE4
|
||||
#define IO_ADDR_E5 0xE5
|
||||
#define IO_ADDR_E6 0xE6
|
||||
#define IO_ADDR_E7 0xE7
|
||||
#define IO_ADDR_E8 0xE8
|
||||
#define IO_ADDR_E9 0xE9
|
||||
#define IO_ADDR_EA 0xEA
|
||||
#define IO_ADDR_EB 0xEB
|
||||
|
||||
|
||||
enum Z80_RUN_STATES {
|
||||
Z80_STOP = 0x00,
|
||||
Z80_STOPPED = 0x01,
|
||||
Z80_PAUSE = 0x02,
|
||||
Z80_PAUSED = 0x03,
|
||||
Z80_CONTINUE = 0x04,
|
||||
Z80_RUNNING = 0x05,
|
||||
};
|
||||
enum Z80_MEMORY_PROFILE {
|
||||
USE_PHYSICAL_RAM = 0x00,
|
||||
USE_VIRTUAL_RAM = 0x01
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// Main memory, linear but indexed as though it were banks in 1K pages.
|
||||
uint8_t memory[Z80_VIRTUAL_MEMORY_SIZE];
|
||||
|
||||
// Page pointer map.
|
||||
//
|
||||
// Each pointer points to a byte or block of bytes in the Z80 Memory frame, 64K Real + Banked.
|
||||
// This is currently set at a block of size 0x800 per memory pointer for the MZ-700.
|
||||
// The LSB of the pointer is a direct memory index to a byte or block of bytes, the upper byte of the pointer indicates type of memory space.
|
||||
// 0x80<FFFFFF> - physical host RAM
|
||||
// 0x40<FFFFFF> - physical host ROM
|
||||
// 0x20<FFFFFF> - physical host VRAM
|
||||
// 0x10<FFFFFF> - physical host hardware
|
||||
// 0x08<FFFFFF> - virtual host RAM
|
||||
// 0x04<FFFFFF> - virtual host ROM
|
||||
// 0x02<FFFFFF> - virtual host hardware
|
||||
// 16bit Input Address -> map -> Pointer to 24bit memory address + type flag.
|
||||
// -> Pointer+<low bits of address> to 24bit memory address + type flag.
|
||||
uint32_t page[MEMORY_BLOCK_SLOTS];
|
||||
uint32_t shadowPage[MEMORY_BLOCK_SLOTS];
|
||||
|
||||
// I/O Page map.
|
||||
//
|
||||
// This is a map to indicate the use of the I/O page and allow any required remapping.
|
||||
// <0x80>FF<I/O Address> - physical host hardware
|
||||
// <0x40>FF<I/O Address> - virtual host hardware
|
||||
// 16bit Input Address -> map -> Actual 16bit address to use + type flag.
|
||||
uint32_t iopage[65536];
|
||||
|
||||
// Default page mode configured. This value reflects the default page and iotable map.
|
||||
uint8_t defaultPageMode;
|
||||
|
||||
// Refresh DRAM mode. 1 = Refresh, 0 = No refresh. Only applicable when running code in virtual Kernel RAM.
|
||||
uint8_t refreshDRAM;
|
||||
|
||||
// Inhibit mode is where certain memory ranges are inhibitted. The memory page is set to inhibit and this flag
|
||||
// blocks actions which arent allowed during inhibit.
|
||||
uint8_t inhibitMode;
|
||||
|
||||
// Address caching. Used to minimise instruction length sent to CPLD.
|
||||
uint16_t z80PrevAddr;
|
||||
uint16_t z80PrevPort;
|
||||
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
uint8_t lowMemorySwap;
|
||||
#endif
|
||||
|
||||
// Keyboard strobe and data. Required to detect hotkey press.
|
||||
uint8_t keyportStrobe;
|
||||
uint8_t keyportShiftCtrl;
|
||||
uint8_t keyportHotKey;
|
||||
|
||||
// Governor is the delay in a 32bit loop per Z80 opcode, used to govern execution speed when using virtual memory.
|
||||
// This mechanism will eventually be tied into the M/T-state calculation for a more precise delay, but at the moment,
|
||||
// with the Z80 assigned to an isolated CPU, it allows time sensitive tasks such as the tape recorder to work.
|
||||
// The lower the value the faster the CPU speed. Two values are present as the optimiser, seeing ROM code not changing
|
||||
// is quicker than RAM (both are in the same kernel memory) as a pointer calculation needs to be made.
|
||||
uint32_t cpuGovernorDelayROM;
|
||||
uint32_t cpuGovernorDelayRAM;
|
||||
} t_Z80Ctrl;
|
||||
|
||||
// IOCTL structure for passing data from user space to driver to perform commands.
|
||||
//
|
||||
struct z80_addr {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
uint32_t size;
|
||||
};
|
||||
struct z80_ctrl {
|
||||
uint16_t pc;
|
||||
};
|
||||
struct speed {
|
||||
uint32_t speedMultiplier;
|
||||
};
|
||||
struct cpld_ctrl {
|
||||
uint32_t cmd;
|
||||
};
|
||||
struct ioctlCmd {
|
||||
int32_t cmd;
|
||||
union {
|
||||
struct z80_addr addr;
|
||||
struct z80_ctrl z80;
|
||||
struct speed speed;
|
||||
struct cpld_ctrl cpld;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Prototypes.
|
||||
void setupMemory(enum Z80_MEMORY_PROFILE mode);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,428 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface
|
||||
// This file contains the methods used in interfacing the SOM to the Z80 socket
|
||||
// and host hardware via a CPLD.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// User space driver access.
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// Initialise the SOM hardware used to communicate with the z80 socket and host hardware.
|
||||
// The SOM interfaces to a CPLD which provides voltage level translation and also encapsulates the Z80 timing cycles as recreating
|
||||
// them within the SOM is much more tricky.
|
||||
//
|
||||
// As this is an embedded device and performance/latency are priorities, minimal structured code is used to keep call stack and
|
||||
// generated code to a mimimum without relying on the optimiser.
|
||||
int z80io_init(void)
|
||||
{
|
||||
// Locals.
|
||||
int ret = 0;
|
||||
|
||||
// Initialise GPIO. We call the HAL api to minimise time but for actual bit set/reset and read we go directly to registers to save time, increase throughput and minimise latency.
|
||||
// Initialise the HAL.
|
||||
MHal_GPIO_Init();
|
||||
|
||||
// Set the pads as GPIO devices. The HAL takes care of allocating and deallocating the padmux resources.
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_0); // Word (16bit) bidirectional bus. Default is read with data set.
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_1);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_2);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_3);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_4);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_5);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_6);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_7);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_HIGH_BYTE);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO8); // SPIO 4wire control lines setup by the spidev driver but controlled directly in this driver.
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO9);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO10);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO11);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_READY);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_LTSTATE);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSRQ);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSACK);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_INT);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_NMI);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WAIT);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RESET);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RSV1);
|
||||
#ifdef NOTNEEDED
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_0);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_1);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_2);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_3);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_4);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_5);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_6);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_7);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WRITE);
|
||||
#endif
|
||||
|
||||
// Set required input pads.
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_0);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_1);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_2);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_3);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_4);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_5);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_6);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_7);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_READY);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_LTSTATE);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSRQ);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSACK);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_INT);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_NMI);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_WAIT);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RESET);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RSV1);
|
||||
|
||||
// Set required output pads.
|
||||
#ifdef NOTNEEDED
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_0);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_1);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_2);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_3);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_4);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_5);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_6);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_7);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_WRITE);
|
||||
MHal_GPIO_Pull_High(PAD_Z80IO_WRITE);
|
||||
#endif
|
||||
|
||||
// Control signals.
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_HIGH_BYTE);
|
||||
MHal_GPIO_Pull_High(PAD_Z80IO_HIGH_BYTE);
|
||||
|
||||
// Setup the MSPI0 device.
|
||||
//
|
||||
// Setup control, interrupts are not used.
|
||||
MSPI_WRITE(MSPI_CTRL_OFFSET, MSPI_CPU_CLOCK_1_2 | MSPI_CTRL_CPOL_LOW | MSPI_CTRL_CPHA_HIGH | MSPI_CTRL_RESET | MSPI_CTRL_ENABLE_SPI);
|
||||
|
||||
// Setup LSB First mode.
|
||||
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, 0x0);
|
||||
|
||||
// Setup clock.
|
||||
CLK_WRITE(MSPI0_CLK_CFG, 0x1100)
|
||||
|
||||
// Setup the frame size (all buffers to 8bits).
|
||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+1, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+1, 0xfff);
|
||||
|
||||
// Setup Chip Selects to inactive.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Switch Video and Audio to host.
|
||||
z80io_SPI_Send16(0x00f0, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Parallel bus Methods.
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Methods to read data from the parallel bus.
|
||||
// The CPLD returns status and Z80 data on the 8bit bus as it is marginally quicker than retrieving it over the SPI bus.
|
||||
//
|
||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
|
||||
// Byte according to flag.
|
||||
if(dataFlag)
|
||||
SET_CPLD_READ_DATA()
|
||||
else
|
||||
SET_CPLD_READ_STATUS()
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result = READ_CPLD_DATA_IN();
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint16_t z80io_PRL_Read16(void)
|
||||
{
|
||||
// Locals.
|
||||
uint16_t result = 0;
|
||||
|
||||
// Low byte first.
|
||||
CLEAR_CPLD_HIGH_BYTE();
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result = (uint16_t)READ_CPLD_DATA_IN();
|
||||
|
||||
// High byte next.
|
||||
SET_CPLD_HIGH_BYTE();
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result |= (uint16_t)(READ_CPLD_DATA_IN() << 8);
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
// Parallel Bus methods were tried and tested but due to the GPIO bits being controlled by individual registers per bit, the setup time was longer
|
||||
// than the transmission time of SPI. These methods are thus deprecated and a fusion of SPI and 8bit parallel is now used.
|
||||
#ifdef NOTNEEDED
|
||||
inline uint8_t z80io_PRL_Send8(uint8_t txData)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
|
||||
// Low byte only.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
||||
|
||||
// Setup data.
|
||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
inline uint8_t z80io_PRL_Send16(uint16_t txData)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
|
||||
// Low byte first.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
||||
|
||||
// Setup data.
|
||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
// High byte next.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
|
||||
// Setup high byte.
|
||||
if(txData & 0x8000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x4000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x2000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x1000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0800) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0400) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0200) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0100) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// SPI Methods.
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Methods to send 8,16 or 32 bits. Each method is seperate to minimise logic and execution time, 8bit being most sensitive.
|
||||
// Macros have also been defined for inline inclusion which dont read back the response data.
|
||||
//
|
||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = (uint8_t)MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, txData);
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)(txData >> 16));
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = (uint32_t)(MSPI_READ(MSPI_FULL_DEPLUX_RD00) | (MSPI_READ(MSPI_FULL_DEPLUX_RD02) << 16));
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
#ifdef INCLUDE_TEST_METHODS
|
||||
#include "z80io_test.c"
|
||||
#else
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
{
|
||||
pr_info("Z80 Test Memory functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
uint8_t z80io_SPI_Test(void)
|
||||
{
|
||||
pr_info("SPI Test functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
uint8_t z80io_PRL_Test(void)
|
||||
{
|
||||
pr_info("Parallel Bus Test functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
483
software/FusionX/src/z80drv/MZ2000/z80io.h
vendored
483
software/FusionX/src/z80drv/MZ2000/z80io.h
vendored
@@ -1,483 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface
|
||||
// This file contains the declarations used in interfacing the SOM to the Z80 socket
|
||||
// and host hardware via a CPLD.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80IO_H
|
||||
#define Z80IO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Definitions to control compilation.
|
||||
#define INCLUDE_TEST_METHODS 1
|
||||
|
||||
// CPLD Commands.
|
||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
||||
#define CPLD_CMD_FETCH_ADDR_P1 0x11
|
||||
#define CPLD_CMD_FETCH_ADDR_P2 0x12
|
||||
#define CPLD_CMD_FETCH_ADDR_P3 0x13
|
||||
#define CPLD_CMD_FETCH_ADDR_P4 0x14
|
||||
#define CPLD_CMD_FETCH_ADDR_P5 0x15
|
||||
#define CPLD_CMD_FETCH_ADDR_P6 0x16
|
||||
#define CPLD_CMD_FETCH_ADDR_P7 0x17
|
||||
#define CPLD_CMD_WRITE_ADDR 0x18
|
||||
#define CPLD_CMD_WRITE_ADDR_P1 0x19
|
||||
#define CPLD_CMD_WRITE_ADDR_P2 0x1A
|
||||
#define CPLD_CMD_WRITE_ADDR_P3 0x1B
|
||||
#define CPLD_CMD_WRITE_ADDR_P4 0x1C
|
||||
#define CPLD_CMD_WRITE_ADDR_P5 0x1D
|
||||
#define CPLD_CMD_WRITE_ADDR_P6 0x1E
|
||||
#define CPLD_CMD_WRITE_ADDR_P7 0x1F
|
||||
#define CPLD_CMD_READ_ADDR 0x20
|
||||
#define CPLD_CMD_READ_ADDR_P1 0x21
|
||||
#define CPLD_CMD_READ_ADDR_P2 0x22
|
||||
#define CPLD_CMD_READ_ADDR_P3 0x23
|
||||
#define CPLD_CMD_READ_ADDR_P4 0x24
|
||||
#define CPLD_CMD_READ_ADDR_P5 0x25
|
||||
#define CPLD_CMD_READ_ADDR_P6 0x26
|
||||
#define CPLD_CMD_READ_ADDR_P7 0x27
|
||||
#define CPLD_CMD_WRITEIO_ADDR 0x28
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P1 0x29
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P2 0x2A
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P3 0x2B
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P4 0x2C
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P5 0x2D
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P6 0x2E
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P7 0x2F
|
||||
#define CPLD_CMD_READIO_ADDR 0x30
|
||||
#define CPLD_CMD_READIO_ADDR_P1 0x31
|
||||
#define CPLD_CMD_READIO_ADDR_P2 0x32
|
||||
#define CPLD_CMD_READIO_ADDR_P3 0x33
|
||||
#define CPLD_CMD_READIO_ADDR_P4 0x34
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||
#define CPLD_CMD_HALT 0x50
|
||||
#define CPLD_CMD_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
#define CPLD_CMD_SET_AUTO_REFRESH 0xF1
|
||||
#define CPLD_CMD_CLEAR_AUTO_REFRESH 0xF2
|
||||
#define CPLD_CMD_SET_SPI_LOOPBACK 0xFE
|
||||
#define CPLD_CMD_NOP1 0x00
|
||||
#define CPLD_CMD_NOP2 0xFF
|
||||
|
||||
|
||||
// Pad numbers for using the MHal GPIO library.
|
||||
#define PAD_Z80IO_IN_DATA_0 PAD_GPIO0
|
||||
#define PAD_Z80IO_IN_DATA_1 PAD_GPIO1
|
||||
#define PAD_Z80IO_IN_DATA_2 PAD_GPIO2
|
||||
#define PAD_Z80IO_IN_DATA_3 PAD_GPIO3
|
||||
#define PAD_Z80IO_IN_DATA_4 PAD_GPIO4
|
||||
#define PAD_Z80IO_IN_DATA_5 PAD_GPIO5
|
||||
#define PAD_Z80IO_IN_DATA_6 PAD_GPIO6
|
||||
#define PAD_Z80IO_IN_DATA_7 PAD_GPIO7
|
||||
#define PAD_SPIO_0 PAD_GPIO8
|
||||
#define PAD_SPIO_1 PAD_GPIO9
|
||||
#define PAD_SPIO_2 PAD_GPIO10
|
||||
#define PAD_SPIO_3 PAD_GPIO11
|
||||
#define PAD_Z80IO_HIGH_BYTE PAD_SAR_GPIO2 // Byte requiured, 0 = Low Byte, 1 = High Byte.
|
||||
#define PAD_Z80IO_READY PAD_GPIO12
|
||||
#define PAD_Z80IO_LTSTATE PAD_PM_IRIN // IRIN
|
||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
||||
#define PAD_Z80IO_RSV1 PAD_SATA_GPIO // GPIO90
|
||||
|
||||
// Physical register addresses.
|
||||
#define PAD_Z80IO_IN_DATA_0_ADDR 0x103C00
|
||||
#define PAD_Z80IO_IN_DATA_1_ADDR 0x103C02
|
||||
#define PAD_Z80IO_IN_DATA_2_ADDR 0x103C04
|
||||
#define PAD_Z80IO_IN_DATA_3_ADDR 0x103C06
|
||||
#define PAD_Z80IO_IN_DATA_4_ADDR 0x103C08
|
||||
#define PAD_Z80IO_IN_DATA_5_ADDR 0x103C0A
|
||||
#define PAD_Z80IO_IN_DATA_6_ADDR 0x103C0C
|
||||
#define PAD_Z80IO_IN_DATA_7_ADDR 0x103C0E
|
||||
#define PAD_SPIO_0_ADDR 0x103C10
|
||||
#define PAD_SPIO_1_ADDR 0x103C12
|
||||
#define PAD_SPIO_2_ADDR 0x103C14
|
||||
#define PAD_SPIO_3_ADDR 0x103C16
|
||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
||||
#define PAD_Z80IO_LTSTATE_ADDR 0xF28 // IRIN
|
||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
||||
#define PAD_Z80IO_RSV1_ADDR 0x103C8A // GPIO90
|
||||
|
||||
#ifdef NOTNEEDED
|
||||
#define PAD_Z80IO_OUT_DATA_0 PAD_GPIO12
|
||||
#define PAD_Z80IO_OUT_DATA_1 PAD_GPIO13
|
||||
#define PAD_Z80IO_OUT_DATA_2 PAD_GPIO14
|
||||
#define PAD_Z80IO_OUT_DATA_3 PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_OUT_DATA_4 PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_OUT_DATA_5 PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_OUT_DATA_6 PAD_VSYNC_OUT // GPIO86
|
||||
#define PAD_Z80IO_OUT_DATA_7 PAD_SATA_GPIO // GPIO90
|
||||
#define PAD_Z80IO_WRITE PAD_PM_IRIN // Write data clock.
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// The definitions below come from SigmaStar kernel drivers. No header file exists hence the
|
||||
// duplication.
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#define SUPPORT_SPI_1 0
|
||||
#define MAX_SUPPORT_BITS 16
|
||||
|
||||
#define BANK_TO_ADDR32(b) (b<<9)
|
||||
#define BANK_SIZE 0x200
|
||||
|
||||
#define MS_BASE_REG_RIU_PA 0x1F000000
|
||||
#define gChipBaseAddr 0xFD203C00
|
||||
#define gPmSleepBaseAddr 0xFD001C00
|
||||
#define gSarBaseAddr 0xFD002800
|
||||
#define gRIUBaseAddr 0xFD000000
|
||||
#define gMOVDMAAddr 0xFD201600
|
||||
#define gClkBaseAddr 0xFD207000
|
||||
#define gMspBaseAddr 0xfd222000
|
||||
|
||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
|
||||
|
||||
#define MSPI0_BANK_ADDR 0x1110
|
||||
#define MSPI1_BANK_ADDR 0x1111
|
||||
#define CLK__BANK_ADDR 0x1038
|
||||
#define CHIPTOP_BANK_ADDR 0x101E
|
||||
#define MOVDMA_BANK_ADDR 0x100B
|
||||
|
||||
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
|
||||
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
|
||||
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
|
||||
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Hardware Register Capability
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
#define MSPI_WRITE_BUF_OFFSET 0x40
|
||||
#define MSPI_READ_BUF_OFFSET 0x44
|
||||
#define MSPI_WBF_SIZE_OFFSET 0x48
|
||||
#define MSPI_RBF_SIZE_OFFSET 0x48
|
||||
// read/ write buffer size
|
||||
#define MSPI_RWSIZE_MASK 0xFF
|
||||
#define MSPI_RSIZE_BIT_OFFSET 0x8
|
||||
#define MAX_READ_BUF_SIZE 0x8
|
||||
#define MAX_WRITE_BUF_SIZE 0x8
|
||||
// CLK config
|
||||
#define MSPI_CTRL_OFFSET 0x49
|
||||
#define MSPI_CLK_CLOCK_OFFSET 0x49
|
||||
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
|
||||
#define MSPI_CLK_CLOCK_MASK 0xFF
|
||||
#define MSPI_CLK_PHASE_MASK 0x40
|
||||
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
|
||||
#define MSPI_CLK_POLARITY_MASK 0x80
|
||||
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
|
||||
#define MSPI_CLK_PHASE_MAX 0x1
|
||||
#define MSPI_CLK_POLARITY_MAX 0x1
|
||||
#define MSPI_CLK_CLOCK_MAX 0x7
|
||||
#define MSPI_CTRL_CPOL_LOW 0x00
|
||||
#define MSPI_CTRL_CPOL_HIGH 0x80
|
||||
#define MSPI_CTRL_CPHA_LOW 0x00
|
||||
#define MSPI_CTRL_CPHA_HIGH 0x40
|
||||
#define MSPI_CTRL_3WIRE 0x10
|
||||
#define MSPI_CTRL_INTEN 0x04
|
||||
#define MSPI_CTRL_RESET 0x02
|
||||
#define MSPI_CTRL_ENABLE_SPI 0x01
|
||||
// DC config
|
||||
#define MSPI_DC_MASK 0xFF
|
||||
#define MSPI_DC_BIT_OFFSET 0x08
|
||||
#define MSPI_DC_TR_START_OFFSET 0x4A
|
||||
#define MSPI_DC_TRSTART_MAX 0xFF
|
||||
#define MSPI_DC_TR_END_OFFSET 0x4A
|
||||
#define MSPI_DC_TREND_MAX 0xFF
|
||||
#define MSPI_DC_TB_OFFSET 0x4B
|
||||
#define MSPI_DC_TB_MAX 0xFF
|
||||
#define MSPI_DC_TRW_OFFSET 0x4B
|
||||
#define MSPI_DC_TRW_MAX 0xFF
|
||||
// Frame Config
|
||||
#define MSPI_FRAME_WBIT_OFFSET 0x4C
|
||||
#define MSPI_FRAME_RBIT_OFFSET 0x4E
|
||||
#define MSPI_FRAME_BIT_MAX 0x07
|
||||
#define MSPI_FRAME_BIT_MASK 0x07
|
||||
#define MSPI_FRAME_BIT_FIELD 0x03
|
||||
#define MSPI_LSB_FIRST_OFFSET 0x50
|
||||
#define MSPI_TRIGGER_OFFSET 0x5A
|
||||
#define MSPI_DONE_OFFSET 0x5B
|
||||
#define MSPI_DONE_CLEAR_OFFSET 0x5C
|
||||
#define MSPI_CHIP_SELECT_OFFSET 0x5F
|
||||
#define MSPI_CS1_DISABLE 0x01
|
||||
#define MSPI_CS1_ENABLE 0x00
|
||||
#define MSPI_CS2_DISABLE 0x02
|
||||
#define MSPI_CS2_ENABLE 0x00
|
||||
#define MSPI_CS3_DISABLE 0x04
|
||||
#define MSPI_CS3_ENABLE 0x00
|
||||
#define MSPI_CS4_DISABLE 0x08
|
||||
#define MSPI_CS4_ENABLE 0x00
|
||||
#define MSPI_CS5_DISABLE 0x10
|
||||
#define MSPI_CS5_ENABLE 0x00
|
||||
#define MSPI_CS6_DISABLE 0x20
|
||||
#define MSPI_CS6_ENABLE 0x00
|
||||
#define MSPI_CS7_DISABLE 0x40
|
||||
#define MSPI_CS7_ENABLE 0x00
|
||||
#define MSPI_CS8_DISABLE 0x80
|
||||
#define MSPI_CS8_ENABLE 0x00
|
||||
|
||||
#define MSPI_FULL_DEPLUX_RD_CNT (0x77)
|
||||
#define MSPI_FULL_DEPLUX_RD00 (0x78)
|
||||
#define MSPI_FULL_DEPLUX_RD01 (0x78)
|
||||
#define MSPI_FULL_DEPLUX_RD02 (0x79)
|
||||
#define MSPI_FULL_DEPLUX_RD03 (0x79)
|
||||
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
|
||||
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
|
||||
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
|
||||
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
|
||||
|
||||
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
|
||||
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
|
||||
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
|
||||
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
|
||||
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
|
||||
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
|
||||
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
|
||||
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
|
||||
|
||||
//chip select bit map
|
||||
#define MSPI_CHIP_SELECT_MAX 0x07
|
||||
|
||||
// control bit
|
||||
#define MSPI_DONE_FLAG 0x01
|
||||
#define MSPI_TRIGGER 0x01
|
||||
#define MSPI_CLEAR_DONE 0x01
|
||||
#define MSPI_INT_ENABLE 0x04
|
||||
#define MSPI_RESET 0x02
|
||||
#define MSPI_ENABLE 0x01
|
||||
|
||||
// clk_mspi0
|
||||
#define MSPI0_CLK_CFG 0x33 //bit 2 ~bit 3
|
||||
#define MSPI0_CLK_108M 0x00
|
||||
#define MSPI0_CLK_54M 0x04
|
||||
#define MSPI0_CLK_12M 0x08
|
||||
#define MSPI0_CLK_MASK 0x0F
|
||||
|
||||
// clk_mspi1
|
||||
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
|
||||
#define MSPI1_CLK_108M 0x0000
|
||||
#define MSPI1_CLK_54M 0x0400
|
||||
#define MSPI1_CLK_12M 0x0800
|
||||
#define MSPI1_CLK_MASK 0x0F00
|
||||
|
||||
// clk_mspi
|
||||
#define MSPI_CLK_CFG 0x33
|
||||
#define MSPI_SELECT_0 0x0000
|
||||
#define MSPI_SELECT_1 0x4000
|
||||
#define MSPI_CLK_MASK 0xF000
|
||||
|
||||
// Clock settings
|
||||
#define MSPI_CPU_CLOCK_1_2 0x0000
|
||||
#define MSPI_CPU_CLOCK_1_4 0x0100
|
||||
#define MSPI_CPU_CLOCK_1_8 0x0200
|
||||
#define MSPI_CPU_CLOCK_1_16 0x0300
|
||||
#define MSPI_CPU_CLOCK_1_32 0x0400
|
||||
#define MSPI_CPU_CLOCK_1_64 0x0500
|
||||
#define MSPI_CPU_CLOCK_1_128 0x0600
|
||||
#define MSPI_CPU_CLOCK_1_256 0x0700
|
||||
|
||||
//CHITOP 101E mspi mode select
|
||||
#define MSPI0_MODE 0x0C //bit0~bit1
|
||||
#define MSPI0_MODE_MASK 0x07
|
||||
#define MSPI1_MODE 0x0C //bit4~bit5
|
||||
#define MSPI1_MODE_MASK 0x70
|
||||
#define EJTAG_MODE 0xF
|
||||
#define EJTAG_MODE_1 0x01
|
||||
#define EJTAG_MODE_2 0x02
|
||||
#define EJTAG_MODE_3 0x03
|
||||
#define EJTAG_MODE_MASK 0x03
|
||||
|
||||
//MOVDMA 100B
|
||||
#define MOV_DMA_SRC_ADDR_L 0x03
|
||||
#define MOV_DMA_SRC_ADDR_H 0x04
|
||||
#define MOV_DMA_DST_ADDR_L 0x05
|
||||
#define MOV_DMA_DST_ADDR_H 0x06
|
||||
#define MOV_DMA_BYTE_CNT_L 0x07
|
||||
#define MOV_DMA_BYTE_CNT_H 0x08
|
||||
#define DMA_MOVE0_IRQ_CLR 0x28
|
||||
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
|
||||
#define DMA_MOVE0_ENABLE 0x00
|
||||
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
|
||||
#define DMA_READ 0x01
|
||||
#define DMA_WRITE 0x00
|
||||
#define DMA_DEVICE_MODE 0x51
|
||||
#define DMA_DEVICE_SEL 0x52
|
||||
|
||||
//spi dma
|
||||
#define MSPI_DMA_DATA_LENGTH_L 0x30
|
||||
#define MSPI_DMA_DATA_LENGTH_H 0x31
|
||||
#define MSPI_DMA_ENABLE 0x32
|
||||
#define MSPI_DMA_RW_MODE 0x33
|
||||
#define MSPI_DMA_WRITE 0x00
|
||||
#define MSPI_DMA_READ 0x01
|
||||
|
||||
#define MSTAR_SPI_TIMEOUT_MS 30000
|
||||
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Macros
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
|
||||
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
|
||||
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
|
||||
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
|
||||
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
|
||||
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
|
||||
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
|
||||
#define READ_CPLD_DATA_IN() ((MHal_RIU_REG(PAD_Z80IO_IN_DATA_7_ADDR) & 0x1) << 7 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_6_ADDR) & 0x1) << 6 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_5_ADDR) & 0x1) << 5 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_4_ADDR) & 0x1) << 4 |\
|
||||
(MHal_RIU_REG(PAD_Z80IO_IN_DATA_3_ADDR) & 0x1) << 3 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_2_ADDR) & 0x1) << 2 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_1_ADDR) & 0x1) << 1 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_0_ADDR) & 0x1))
|
||||
#define SET_CPLD_READ_DATA() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
||||
#define SET_CPLD_READ_STATUS() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
||||
#define SET_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
||||
#define CLEAR_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
||||
#define CPLD_READY() (MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1)
|
||||
#define CPLD_RESET() (MHal_RIU_REG(PAD_Z80IO_RESET_ADDR) & 0x1)
|
||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
// write 2 byte
|
||||
//#define MSPI_WRITE(_reg_, _val_) {pr_info("PDS: MSPI_WRITE(0x%x, 0x%x, 0x%x)\n", _reg_, _val_, gMspBaseAddr + ((_reg_)<<2)); WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define MSPI_WRITE(_reg_, _val_) WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_));
|
||||
//write 2 byte mask
|
||||
//#define MSPI_WRITE_MASK(_reg_, _val_, mask) {pr_info("PDS: WRITE_LONG(0x%x, 0x%x, mask=0x%x)\n", _reg_, _val_, mask); WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask)); }
|
||||
#define MSPI_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask));
|
||||
|
||||
#define CLK_READ(_reg_) READ_WORD(gClkBaseAddr + ((_reg_)<<2))
|
||||
//#define CLK_WRITE(_reg_, _val_) {pr_info("PDS: CLK_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define CLK_WRITE(_reg_, _val_) WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define CHIPTOP_READ(_reg_) READ_WORD(gChipBaseAddr + ((_reg_)<<2))
|
||||
//#define CHIPTOP_WRITE(_reg_, _val_) {pr_info("PDS: CHIPTOP_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define CHIPTOP_WRITE(_reg_, _val_) WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define MOVDMA_READ(_reg_) READ_WORD(gMOVDMAAddr + ((_reg_)<<2))
|
||||
//#define MOVDMA_WRITE(_reg_, _val_) {pr_info("PDS: MOVDMA_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define MOVDMA_WRITE(_reg_, _val_) WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
|
||||
#define MAX_CHECK_CNT 2000
|
||||
|
||||
#define MSPI_READ_INDEX 0x0
|
||||
#define MSPI_WRITE_INDEX 0x1
|
||||
|
||||
#define SPI_MIU0_BUS_BASE 0x20000000
|
||||
#define SPI_MIU1_BUS_BASE 0xFFFFFFFF
|
||||
|
||||
|
||||
// Function definitions.
|
||||
//
|
||||
int z80io_init(void);
|
||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData);
|
||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData);
|
||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
||||
#ifdef NOTNEEDED
|
||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
||||
#endif
|
||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
||||
uint16_t z80io_PRL_Read16(void);
|
||||
uint8_t z80io_SPI_Test(void);
|
||||
uint8_t z80io_PRL_Test(void);
|
||||
uint8_t z80io_Z80_TestMemory(void);
|
||||
|
||||
extern void MHal_GPIO_Init(void);
|
||||
extern void MHal_GPIO_Pad_Set(uint8_t u8IndexGPIO);
|
||||
extern int MHal_GPIO_PadGroupMode_Set(uint32_t u32PadMode);
|
||||
extern int MHal_GPIO_PadVal_Set(uint8_t u8IndexGPIO, uint32_t u32PadMode);
|
||||
extern void MHal_GPIO_Pad_Oen(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pad_Odn(uint8_t u8IndexGPIO);
|
||||
extern uint8_t MHal_GPIO_Pad_Level(uint8_t u8IndexGPIO);
|
||||
extern uint8_t MHal_GPIO_Pad_InOut(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pull_High(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pull_Low(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_High(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_Low(uint8_t u8IndexGPIO);
|
||||
extern void MHal_Enable_GPIO_INT(uint8_t u8IndexGPIO);
|
||||
extern int MHal_GPIO_To_Irq(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_POLARITY(uint8_t u8IndexGPIO, uint8_t reverse);
|
||||
extern void MHal_GPIO_Set_Driving(uint8_t u8IndexGPIO, uint8_t setHigh);
|
||||
extern void MHal_GPIO_PAD_32K_OUT(uint8_t u8Enable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // Z80IO_H
|
||||
@@ -1,541 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io_test.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface Test Methods
|
||||
// This file contains the methods used to test the SOM to CPLD interface and evaluate
|
||||
// it's performance. Production builds wont include these methods.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
uint32_t addr;
|
||||
uint32_t fullCmd;
|
||||
uint8_t cmd;
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 100;
|
||||
uint32_t errorCount;
|
||||
uint32_t idx;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
uint8_t result;
|
||||
spinlock_t spinLock;
|
||||
unsigned long flags;
|
||||
|
||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||
|
||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E80000 | (0x82 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E20000 | (0x58 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E00000 | (0xF7 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E90000 | (0x0F << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00EB0000 | (0xCF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00EB0000 | (0xFF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
pr_info("Z80 Host Test - IO.\n");
|
||||
// for(idx=0; idx < 1000000; idx++)
|
||||
// {
|
||||
// SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
// SPI_SEND32(0xD0000000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// SPI_SEND32(0xD0100000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// SPI_SEND32(0xD0200000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// SPI_SEND32(0xD0300000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// SPI_SEND32(0xD0400000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// SPI_SEND32(0xD0500000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
// }
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing IO Write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
for(addr=0x0000; addr < 0x10000; addr++)
|
||||
{
|
||||
fullCmd = 0x00000000| ((uint8_t)addr) << 8 | CPLD_CMD_WRITEIO_ADDR;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing IO Read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible IO ports and write to it.
|
||||
for(addr=0x0000; addr < 0x10000; addr++)
|
||||
{
|
||||
fullCmd = 0x00000000 | ((uint8_t)addr) << 8 | CPLD_CMD_READIO_ADDR;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing RAM Write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write performance (opt).\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write/Fetch performance (opt).\n");
|
||||
errorCount = 0;
|
||||
SET_CPLD_READ_DATA();
|
||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x8000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x8000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x10;
|
||||
SPI_SEND8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
if(result != (uint8_t)addr)
|
||||
{
|
||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write/Read performance (opt).\n");
|
||||
errorCount = 0;
|
||||
SET_CPLD_READ_DATA();
|
||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x8000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x8000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x20;
|
||||
SPI_SEND8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
if(result != (uint8_t)addr)
|
||||
{
|
||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Fetch performance.\n");
|
||||
SET_CPLD_READ_DATA();
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and read from it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x10;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x11;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Read performance (opt).\n");
|
||||
SET_CPLD_READ_DATA();
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and read from it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x20;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x21;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// Go through all the accessible attribute VRAM and initialise it.
|
||||
pr_info("Z80 Host Test - Testing VRAM Write performance.\n");
|
||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
iterations = 256*10;
|
||||
do_gettimeofday(&start);
|
||||
for(addr=0xD800; addr < 0xE000; addr++)
|
||||
{
|
||||
//while(CPLD_READY() == 0);
|
||||
if(addr == 0xD800)
|
||||
{
|
||||
fullCmd = (addr << 16) |(0x71 << 8) | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
}
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible VRAM and write to it.
|
||||
for(addr=0xD000; addr < 0xD800; addr++)
|
||||
{
|
||||
//while(CPLD_READY() == 0);
|
||||
if(addr == 0xD000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)idx << 8) | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)((1*iterations*0x800)+0x800)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
// A simple test to verify the SOM to CPLD SPI connectivity and give an estimate of its performance.
|
||||
// The performance is based on the SPI setup and transmit time along with the close and received data processing.
|
||||
// In real use, the driver will just send a command and generally ignore received data so increased throughput can be achieved.
|
||||
//
|
||||
uint8_t z80io_SPI_Test(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 10000000;
|
||||
uint32_t idx;
|
||||
uint8_t rxData8;
|
||||
uint16_t rxData16;
|
||||
uint16_t rxData16Last;
|
||||
uint32_t rxData32;
|
||||
uint32_t rxData32Last;
|
||||
uint32_t errorCount;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
|
||||
// Place the CPLD into echo test mode.
|
||||
z80io_SPI_Send8(0xfe, &rxData8);
|
||||
|
||||
// 1st. test, 8bit.
|
||||
pr_info("SPI Test - Testing 8 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
z80io_SPI_Send8((uint8_t)idx, &rxData8);
|
||||
if(idx > 1 && (uint8_t)(idx-1) != rxData8)
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint8_t)(idx-1), rxData8 );
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 2nd. test, 16bit.
|
||||
pr_info("SPI Test - Testing 16 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
||||
z80io_SPI_Send16((uint16_t)idx, &rxData16);
|
||||
if(idx > 0 && (uint16_t)(idx-1) != (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)))
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint16_t)(idx-1), (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)));
|
||||
errorCount++;
|
||||
}
|
||||
rxData16Last = rxData16;
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 3rd. test, 32bit.
|
||||
pr_info("SPI Test - Testing 32 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
z80io_SPI_Send32((uint32_t)idx, &rxData32);
|
||||
if(idx > 0 && (uint32_t)(idx-1) != (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)))
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint32_t)(idx-1), (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)));
|
||||
errorCount++;
|
||||
}
|
||||
rxData32Last = rxData32;
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(4*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
// Method to test the parallel bus, verifying integrity and assessing performance.
|
||||
uint8_t z80io_PRL_Test(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 10000000;
|
||||
uint32_t idx;
|
||||
uint8_t rxData8;
|
||||
uint16_t rxData16;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
#ifdef NOTNEEDED
|
||||
uint32_t errorCount;
|
||||
#endif
|
||||
|
||||
// Place the CPLD into echo test mode.
|
||||
|
||||
// 1st. test, 8bit RW.
|
||||
#ifdef NOTNEEDED
|
||||
pr_info("Parallel Test - Testing 8 bit r/w performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write byte and readback to compare.
|
||||
z80io_PRL_Send8((uint8_t)idx);
|
||||
rxData8 = z80io_PRL_Read8();
|
||||
if((uint8_t)idx != rxData8)
|
||||
{
|
||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint8_t)(idx), rxData8);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 2nd. test, 8bit Write.
|
||||
pr_info("Parallel Test - Testing 8 bit write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write byte.
|
||||
z80io_PRL_Send8((uint8_t)idx);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
#endif
|
||||
|
||||
// 3rd. test, 8bit Read.
|
||||
pr_info("Parallel Test - Testing 8 bit read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Read byte.
|
||||
rxData8 = z80io_PRL_Read8(0);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
#ifdef NOTNEEDED
|
||||
// 4th test, 16bit.
|
||||
pr_info("Parallel Test - Testing 16 bit r/w performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
||||
z80io_PRL_Send16((uint16_t)idx);
|
||||
rxData16 = z80io_PRL_Read16();
|
||||
if((uint16_t)idx != rxData16)
|
||||
{
|
||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint16_t)(idx), rxData16);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 5th test, 16bit Write.
|
||||
pr_info("Parallel Test - Testing 16 bit write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write word.
|
||||
z80io_PRL_Send16((uint16_t)idx);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
#endif
|
||||
|
||||
// 6th test, 16bit Read.
|
||||
pr_info("Parallel Test - Testing 16 bit read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Read word.
|
||||
rxData16 = z80io_PRL_Read16();
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
||||
return(0);
|
||||
}
|
||||
403
software/FusionX/src/z80drv/MZ700/optparse.h
vendored
403
software/FusionX/src/z80drv/MZ700/optparse.h
vendored
@@ -1,403 +0,0 @@
|
||||
/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* To get the implementation, define OPTPARSE_IMPLEMENTATION.
|
||||
* Optionally define OPTPARSE_API to control the API's visibility
|
||||
* and/or linkage (static, __attribute__, __declspec).
|
||||
*
|
||||
* The POSIX getopt() option parser has three fatal flaws. These flaws
|
||||
* are solved by Optparse.
|
||||
*
|
||||
* 1) Parser state is stored entirely in global variables, some of
|
||||
* which are static and inaccessible. This means only one thread can
|
||||
* use getopt(). It also means it's not possible to recursively parse
|
||||
* nested sub-arguments while in the middle of argument parsing.
|
||||
* Optparse fixes this by storing all state on a local struct.
|
||||
*
|
||||
* 2) The POSIX standard provides no way to properly reset the parser.
|
||||
* This means for portable code that getopt() is only good for one
|
||||
* run, over one argv with one option string. It also means subcommand
|
||||
* options cannot be processed with getopt(). Most implementations
|
||||
* provide a method to reset the parser, but it's not portable.
|
||||
* Optparse provides an optparse_arg() function for stepping over
|
||||
* subcommands and continuing parsing of options with another option
|
||||
* string. The Optparse struct itself can be passed around to
|
||||
* subcommand handlers for additional subcommand option parsing. A
|
||||
* full reset can be achieved by with an additional optparse_init().
|
||||
*
|
||||
* 3) Error messages are printed to stderr. This can be disabled with
|
||||
* opterr, but the messages themselves are still inaccessible.
|
||||
* Optparse solves this by writing an error message in its errmsg
|
||||
* field. The downside to Optparse is that this error message will
|
||||
* always be in English rather than the current locale.
|
||||
*
|
||||
* Optparse should be familiar with anyone accustomed to getopt(), and
|
||||
* it could be a nearly drop-in replacement. The option string is the
|
||||
* same and the fields have the same names as the getopt() global
|
||||
* variables (optarg, optind, optopt).
|
||||
*
|
||||
* Optparse also supports GNU-style long options with optparse_long().
|
||||
* The interface is slightly different and simpler than getopt_long().
|
||||
*
|
||||
* By default, argv is permuted as it is parsed, moving non-option
|
||||
* arguments to the end. This can be disabled by setting the `permute`
|
||||
* field to 0 after initialization.
|
||||
*/
|
||||
#ifndef OPTPARSE_H
|
||||
#define OPTPARSE_H
|
||||
|
||||
#ifndef OPTPARSE_API
|
||||
# define OPTPARSE_API
|
||||
#endif
|
||||
|
||||
struct optparse {
|
||||
char **argv;
|
||||
int permute;
|
||||
int optind;
|
||||
int optopt;
|
||||
char *optarg;
|
||||
char errmsg[64];
|
||||
int subopt;
|
||||
};
|
||||
|
||||
enum optparse_argtype {
|
||||
OPTPARSE_NONE,
|
||||
OPTPARSE_REQUIRED,
|
||||
OPTPARSE_OPTIONAL
|
||||
};
|
||||
|
||||
struct optparse_long {
|
||||
const char *longname;
|
||||
int shortname;
|
||||
enum optparse_argtype argtype;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the parser state.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
void optparse_init(struct optparse *options, char **argv);
|
||||
|
||||
/**
|
||||
* Read the next option in the argv array.
|
||||
* @param optstring a getopt()-formatted option string.
|
||||
* @return the next option character, -1 for done, or '?' for error
|
||||
*
|
||||
* Just like getopt(), a character followed by no colons means no
|
||||
* argument. One colon means the option has a required argument. Two
|
||||
* colons means the option takes an optional argument.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
int optparse(struct optparse *options, const char *optstring);
|
||||
|
||||
/**
|
||||
* Handles GNU-style long options in addition to getopt() options.
|
||||
* This works a lot like GNU's getopt_long(). The last option in
|
||||
* longopts must be all zeros, marking the end of the array. The
|
||||
* longindex argument may be NULL.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
int optparse_long(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex);
|
||||
|
||||
/**
|
||||
* Used for stepping over non-option arguments.
|
||||
* @return the next non-option argument, or NULL for no more arguments
|
||||
*
|
||||
* Argument parsing can continue with optparse() after using this
|
||||
* function. That would be used to parse the options for the
|
||||
* subcommand returned by optparse_arg(). This function allows you to
|
||||
* ignore the value of optind.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
char *optparse_arg(struct optparse *options);
|
||||
|
||||
/* Implementation */
|
||||
#ifdef OPTPARSE_IMPLEMENTATION
|
||||
|
||||
#define OPTPARSE_MSG_INVALID "invalid option"
|
||||
#define OPTPARSE_MSG_MISSING "option requires an argument"
|
||||
#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
|
||||
|
||||
static int
|
||||
optparse_error(struct optparse *options, const char *msg, const char *data)
|
||||
{
|
||||
unsigned p = 0;
|
||||
const char *sep = " -- '";
|
||||
while (*msg)
|
||||
options->errmsg[p++] = *msg++;
|
||||
while (*sep)
|
||||
options->errmsg[p++] = *sep++;
|
||||
while (p < sizeof(options->errmsg) - 2 && *data)
|
||||
options->errmsg[p++] = *data++;
|
||||
options->errmsg[p++] = '\'';
|
||||
options->errmsg[p++] = '\0';
|
||||
return '?';
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
void
|
||||
optparse_init(struct optparse *options, char **argv)
|
||||
{
|
||||
options->argv = argv;
|
||||
options->permute = 1;
|
||||
options->optind = 1;
|
||||
options->subopt = 0;
|
||||
options->optarg = 0;
|
||||
options->errmsg[0] = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_dashdash(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_shortopt(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_longopt(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
optparse_permute(struct optparse *options, int index)
|
||||
{
|
||||
char *nonoption = options->argv[index];
|
||||
int i;
|
||||
for (i = index; i < options->optind - 1; i++)
|
||||
options->argv[i] = options->argv[i + 1];
|
||||
options->argv[options->optind - 1] = nonoption;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_argtype(const char *optstring, char c)
|
||||
{
|
||||
int count = OPTPARSE_NONE;
|
||||
if (c == ':')
|
||||
return -1;
|
||||
for (; *optstring && c != *optstring; optstring++);
|
||||
if (!*optstring)
|
||||
return -1;
|
||||
if (optstring[1] == ':')
|
||||
count += optstring[2] == ':' ? 2 : 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
int
|
||||
optparse(struct optparse *options, const char *optstring)
|
||||
{
|
||||
int type;
|
||||
char *next;
|
||||
char *option = options->argv[options->optind];
|
||||
options->errmsg[0] = '\0';
|
||||
options->optopt = 0;
|
||||
options->optarg = 0;
|
||||
if (option == 0) {
|
||||
return -1;
|
||||
} else if (optparse_is_dashdash(option)) {
|
||||
options->optind++; /* consume "--" */
|
||||
return -1;
|
||||
} else if (!optparse_is_shortopt(option)) {
|
||||
if (options->permute) {
|
||||
int index = options->optind++;
|
||||
int r = optparse(options, optstring);
|
||||
optparse_permute(options, index);
|
||||
options->optind--;
|
||||
return r;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
option += options->subopt + 1;
|
||||
options->optopt = option[0];
|
||||
type = optparse_argtype(optstring, option[0]);
|
||||
next = options->argv[options->optind + 1];
|
||||
switch (type) {
|
||||
case -1: {
|
||||
char str[2] = {0, 0};
|
||||
str[0] = option[0];
|
||||
options->optind++;
|
||||
return optparse_error(options, OPTPARSE_MSG_INVALID, str);
|
||||
}
|
||||
case OPTPARSE_NONE:
|
||||
if (option[1]) {
|
||||
options->subopt++;
|
||||
} else {
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
}
|
||||
return option[0];
|
||||
case OPTPARSE_REQUIRED:
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
if (option[1]) {
|
||||
options->optarg = option + 1;
|
||||
} else if (next != 0) {
|
||||
options->optarg = next;
|
||||
options->optind++;
|
||||
} else {
|
||||
char str[2] = {0, 0};
|
||||
str[0] = option[0];
|
||||
options->optarg = 0;
|
||||
return optparse_error(options, OPTPARSE_MSG_MISSING, str);
|
||||
}
|
||||
return option[0];
|
||||
case OPTPARSE_OPTIONAL:
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
if (option[1])
|
||||
options->optarg = option + 1;
|
||||
else
|
||||
options->optarg = 0;
|
||||
return option[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
char *
|
||||
optparse_arg(struct optparse *options)
|
||||
{
|
||||
char *option = options->argv[options->optind];
|
||||
options->subopt = 0;
|
||||
if (option != 0)
|
||||
options->optind++;
|
||||
return option;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_longopts_end(const struct optparse_long *longopts, int i)
|
||||
{
|
||||
return !longopts[i].longname && !longopts[i].shortname;
|
||||
}
|
||||
|
||||
static void
|
||||
optparse_from_long(const struct optparse_long *longopts, char *optstring)
|
||||
{
|
||||
char *p = optstring;
|
||||
int i;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
||||
if (longopts[i].shortname && longopts[i].shortname < 127) {
|
||||
int a;
|
||||
*p++ = longopts[i].shortname;
|
||||
for (a = 0; a < (int)longopts[i].argtype; a++)
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* Unlike strcmp(), handles options containing "=". */
|
||||
static int
|
||||
optparse_longopts_match(const char *longname, const char *option)
|
||||
{
|
||||
const char *a = option, *n = longname;
|
||||
if (longname == 0)
|
||||
return 0;
|
||||
for (; *a && *n && *a != '='; a++, n++)
|
||||
if (*a != *n)
|
||||
return 0;
|
||||
return *n == '\0' && (*a == '\0' || *a == '=');
|
||||
}
|
||||
|
||||
/* Return the part after "=", or NULL. */
|
||||
static char *
|
||||
optparse_longopts_arg(char *option)
|
||||
{
|
||||
for (; *option && *option != '='; option++);
|
||||
if (*option == '=')
|
||||
return option + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_long_fallback(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex)
|
||||
{
|
||||
int result;
|
||||
char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
|
||||
optparse_from_long(longopts, optstring);
|
||||
result = optparse(options, optstring);
|
||||
if (longindex != 0) {
|
||||
*longindex = -1;
|
||||
if (result != -1) {
|
||||
int i;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++)
|
||||
if (longopts[i].shortname == options->optopt)
|
||||
*longindex = i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
int
|
||||
optparse_long(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex)
|
||||
{
|
||||
int i;
|
||||
char *option = options->argv[options->optind];
|
||||
if (option == 0) {
|
||||
return -1;
|
||||
} else if (optparse_is_dashdash(option)) {
|
||||
options->optind++; /* consume "--" */
|
||||
return -1;
|
||||
} else if (optparse_is_shortopt(option)) {
|
||||
return optparse_long_fallback(options, longopts, longindex);
|
||||
} else if (!optparse_is_longopt(option)) {
|
||||
if (options->permute) {
|
||||
int index = options->optind++;
|
||||
int r = optparse_long(options, longopts, longindex);
|
||||
optparse_permute(options, index);
|
||||
options->optind--;
|
||||
return r;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse as long option. */
|
||||
options->errmsg[0] = '\0';
|
||||
options->optopt = 0;
|
||||
options->optarg = 0;
|
||||
option += 2; /* skip "--" */
|
||||
options->optind++;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
||||
const char *name = longopts[i].longname;
|
||||
if (optparse_longopts_match(name, option)) {
|
||||
char *arg;
|
||||
if (longindex)
|
||||
*longindex = i;
|
||||
options->optopt = longopts[i].shortname;
|
||||
arg = optparse_longopts_arg(option);
|
||||
if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
|
||||
return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
|
||||
} if (arg != 0) {
|
||||
options->optarg = arg;
|
||||
} else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
|
||||
options->optarg = options->argv[options->optind];
|
||||
if (options->optarg == 0)
|
||||
return optparse_error(options, OPTPARSE_MSG_MISSING, name);
|
||||
else
|
||||
options->optind++;
|
||||
}
|
||||
return options->optopt;
|
||||
}
|
||||
}
|
||||
return optparse_error(options, OPTPARSE_MSG_INVALID, option);
|
||||
}
|
||||
|
||||
#endif /* OPTPARSE_IMPLEMENTATION */
|
||||
#endif /* OPTPARSE_H */
|
||||
@@ -1,734 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80ctrl.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Control Interface
|
||||
// This file contains a command line utility tool for controlling the z80drv device
|
||||
// driver. The tool allows manipulation of the emulated Z80, inspection of its
|
||||
// memory and data, transmission of adhoc commands to the underlying CPLD-Z80
|
||||
// gateway and loading/saving of programs and data to/from the Z80 virtual and
|
||||
// host memory.
|
||||
//
|
||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
||||
// The Z80 CPU Emulator is the heart of the Z80 device driver.
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <sys/select.h>
|
||||
#include <termios.h>
|
||||
#include <time.h>
|
||||
#include <Z/constants/pointer.h>
|
||||
#include <Z/macros/member.h>
|
||||
#include <Z/macros/array.h>
|
||||
#include <Z80.h>
|
||||
#include "z80driver.h"
|
||||
|
||||
#define VERSION "1.0"
|
||||
#define AUTHOR "P.D.Smart"
|
||||
#define COPYRIGHT "(c) 2018-22"
|
||||
|
||||
// Getopt_long is buggy so we use optparse.
|
||||
#define OPTPARSE_IMPLEMENTATION
|
||||
#define OPTPARSE_API static
|
||||
#include "optparse.h"
|
||||
|
||||
// Device driver name.
|
||||
#define DEVICE_FILENAME "/dev/z80drv"
|
||||
|
||||
// Constants for the Sharp MZ80A MZF file format.
|
||||
#define MZF_HEADER_SIZE 128 // Size of the MZF header.
|
||||
#define MZF_ATTRIBUTE 0x00 // Code Type, 01 = Machine Code.
|
||||
#define MZF_FILENAME 0x01 // Title/Name (17 bytes).
|
||||
#define MZF_FILENAME_LEN 17 // Length of the filename, it is not NULL terminated, generally a CR can be taken as terminator but not guaranteed.
|
||||
#define MZF_FILESIZE 0x12 // Size of program.
|
||||
#define MZF_LOADADDR 0x14 // Load address of program.
|
||||
#define MZF_EXECADDR 0x16 // Exec address of program.
|
||||
#define MZF_COMMENT 0x18 // Comment, used for details of the file or startup code.
|
||||
#define MZF_COMMENT_LEN 104 // Length of the comment field.
|
||||
#define CMT_TYPE_OBJCD 0x001 // MZF contains a binary object.
|
||||
#define CMT_TYPE_BTX1CD 0x002 // MZF contains a BASIC program.
|
||||
#define CMT_TYPE_BTX2CD 0x005 // MZF contains a BASIC program.
|
||||
#define CMT_TYPE_TZOBJCD0 0x0F8 // MZF contains a TZFS binary object for page 0.
|
||||
#define CMT_TYPE_TZOBJCD1 0x0F9
|
||||
#define CMT_TYPE_TZOBJCD2 0x0FA
|
||||
#define CMT_TYPE_TZOBJCD3 0x0FB
|
||||
#define CMT_TYPE_TZOBJCD4 0x0FC
|
||||
#define CMT_TYPE_TZOBJCD5 0x0FD
|
||||
#define CMT_TYPE_TZOBJCD6 0x0FE
|
||||
#define CMT_TYPE_TZOBJCD7 0x0FF // MZF contains a TZFS binary object for page 7.
|
||||
#define MZ_CMT_ADDR 0x10F0
|
||||
|
||||
// Structure to define a Sharp MZ80A MZF directory structure. This header appears at the beginning of every Sharp MZ80A tape (and more recently archived/emulator) images.
|
||||
//
|
||||
typedef struct __attribute__((__packed__)) {
|
||||
uint8_t attr; // MZF attribute describing the file.
|
||||
uint8_t fileName[MZF_FILENAME_LEN]; // Each directory entry is the size of an MZF filename.
|
||||
uint16_t fileSize; // Size of file.
|
||||
uint16_t loadAddr; // Load address for the file.
|
||||
uint16_t execAddr; // Execution address where the Z80 starts processing.
|
||||
uint8_t comment[MZF_COMMENT_LEN]; // Text comment field but often contains a startup machine code program.
|
||||
} t_svcDirEnt;
|
||||
|
||||
// Possible commands to be issued to the Z80 driver.
|
||||
enum CTRL_COMMANDS {
|
||||
Z80_CMD_STOP = 0,
|
||||
Z80_CMD_START = 1,
|
||||
Z80_CMD_PAUSE = 2,
|
||||
Z80_CMD_CONTINUE = 3,
|
||||
Z80_CMD_RESET = 4,
|
||||
Z80_CMD_SPEED = 5,
|
||||
Z80_CMD_HOST_RAM = 6,
|
||||
Z80_CMD_VIRTUAL_RAM = 7,
|
||||
Z80_CMD_DUMP_MEMORY = 8,
|
||||
Z80_CMD_MEMORY_TEST = 9,
|
||||
CPLD_CMD_SEND_CMD = 10,
|
||||
CPLD_CMD_SPI_TEST = 11,
|
||||
CPLD_CMD_PRL_TEST = 12
|
||||
};
|
||||
|
||||
|
||||
// Shared memory between this process and the Z80 driver.
|
||||
static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
|
||||
// Method to obtain and return the output screen width.
|
||||
//
|
||||
uint8_t getScreenWidth(void)
|
||||
{
|
||||
return(MAX_SCREEN_WIDTH);
|
||||
}
|
||||
|
||||
struct termios orig_termios;
|
||||
|
||||
void reset_terminal_mode()
|
||||
{
|
||||
tcsetattr(0, TCSANOW, &orig_termios);
|
||||
}
|
||||
|
||||
void set_conio_terminal_mode()
|
||||
{
|
||||
struct termios new_termios;
|
||||
|
||||
/* take two copies - one for now, one for later */
|
||||
tcgetattr(0, &orig_termios);
|
||||
memcpy(&new_termios, &orig_termios, sizeof(new_termios));
|
||||
|
||||
/* register cleanup handler, and set the new terminal mode */
|
||||
atexit(reset_terminal_mode);
|
||||
cfmakeraw(&new_termios);
|
||||
tcsetattr(0, TCSANOW, &new_termios);
|
||||
}
|
||||
|
||||
int kbhit()
|
||||
{
|
||||
struct timeval tv = { 0L, 0L };
|
||||
fd_set fds;
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(0, &fds);
|
||||
return select(1, &fds, NULL, NULL, &tv) > 0;
|
||||
}
|
||||
|
||||
int getch(uint8_t wait)
|
||||
{
|
||||
int r;
|
||||
unsigned char c;
|
||||
|
||||
if(wait != 0 || (wait == 0 && kbhit()))
|
||||
{
|
||||
if ((r = read(0, &c, sizeof(c))) < 0) {
|
||||
return r;
|
||||
} else {
|
||||
return c;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
void delay(int number_of_seconds)
|
||||
{
|
||||
// Converting time into milli_seconds
|
||||
int milli_seconds = 1000 * number_of_seconds;
|
||||
|
||||
// Storing start time
|
||||
clock_t start_time = clock();
|
||||
|
||||
// looping till required time is not achieved
|
||||
while (clock() < start_time + milli_seconds);
|
||||
}
|
||||
|
||||
// Function to dump out a given section of memory via the UART.
|
||||
//
|
||||
int memoryDump(uint32_t memaddr, uint32_t memsize, uint8_t memoryFlag, uint32_t memwidth, uint32_t dispaddr, uint8_t dispwidth)
|
||||
{
|
||||
uint8_t displayWidth = dispwidth;;
|
||||
uint32_t pnt = memaddr;
|
||||
uint32_t endAddr = memaddr + memsize;
|
||||
uint32_t addr = dispaddr;
|
||||
uint32_t i = 0;
|
||||
//uint32_t data;
|
||||
int8_t keyIn;
|
||||
int result = -1;
|
||||
char c = 0;
|
||||
|
||||
// Sanity check. memoryFlag == 0 required kernel driver to dump so we exit as it cannot be performed here.
|
||||
if(memoryFlag == 0)
|
||||
return(-1);
|
||||
|
||||
// Reconfigure terminal to allow non-blocking key input.
|
||||
//
|
||||
set_conio_terminal_mode();
|
||||
|
||||
// If not set, calculate output line width according to connected display width.
|
||||
//
|
||||
if(displayWidth == 0)
|
||||
{
|
||||
switch(getScreenWidth())
|
||||
{
|
||||
case 40:
|
||||
displayWidth = 8;
|
||||
break;
|
||||
case 80:
|
||||
displayWidth = 16;
|
||||
break;
|
||||
default:
|
||||
displayWidth = 32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
printf("%08lX", addr); // print address
|
||||
printf(": ");
|
||||
|
||||
// print hexadecimal data
|
||||
for (i=0; i < displayWidth; )
|
||||
{
|
||||
switch(memwidth)
|
||||
{
|
||||
case 16:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%04X", memoryFlag == 1 ? (uint16_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint16_t)Z80Ctrl->page[pnt+i] : (uint16_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
|
||||
case 32:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%08lX", memoryFlag == 1 ? (uint32_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint32_t)Z80Ctrl->page[pnt+i] : (uint32_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
default:
|
||||
if(pnt+i < endAddr)
|
||||
printf("%02X", memoryFlag == 1 ? (uint8_t)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (uint8_t)Z80Ctrl->page[pnt+i] : (uint8_t)Z80Ctrl->iopage[pnt+i]);
|
||||
else
|
||||
printf(" ");
|
||||
i++;
|
||||
break;
|
||||
}
|
||||
fputc((char)' ', stdout);
|
||||
}
|
||||
|
||||
// print ascii data
|
||||
printf(" |");
|
||||
|
||||
// print single ascii char
|
||||
for (i=0; i < displayWidth; i++)
|
||||
{
|
||||
c = memoryFlag == 1 ? (char)Z80Ctrl->memory[pnt+i] : memoryFlag == 2 ? (char)Z80Ctrl->page[pnt+i] : (char)Z80Ctrl->iopage[pnt+i];
|
||||
if ((pnt+i < endAddr) && (c >= ' ') && (c <= '~'))
|
||||
fputc((char)c, stdout);
|
||||
else
|
||||
fputc((char)' ', stdout);
|
||||
}
|
||||
|
||||
printf("|\r\n");
|
||||
fflush(stdout);
|
||||
|
||||
// Move on one row.
|
||||
pnt += displayWidth;
|
||||
addr += displayWidth;
|
||||
|
||||
// User abort (ESC), pause (Space) or all done?
|
||||
//
|
||||
keyIn = getch(0);
|
||||
if(keyIn == ' ')
|
||||
{
|
||||
do {
|
||||
keyIn = getch(0);
|
||||
} while(keyIn != ' ' && keyIn != 0x1b);
|
||||
}
|
||||
// Escape key pressed, exit with 0 to indicate this to caller.
|
||||
if (keyIn == 0x1b)
|
||||
{
|
||||
sleep(1);
|
||||
result = 0;
|
||||
goto memoryDumpExit;
|
||||
}
|
||||
|
||||
// End of buffer, exit the loop.
|
||||
if(pnt >= (memaddr + memsize))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Normal exit, return -1 to show no key pressed.
|
||||
memoryDumpExit:
|
||||
reset_terminal_mode();
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Method to load a program or data file into the Z80 memory. First load into Virtual memory and then trigger a sync to bring Host RAM in line.
|
||||
//
|
||||
int z80load(int fdZ80, char *fileName)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
t_svcDirEnt mzfHeader;
|
||||
|
||||
// Pause the Z80.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Open the file and read directly into the Virtual memory via the share.
|
||||
FILE *ptr;
|
||||
ptr = fopen(fileName, "rb");
|
||||
if(ptr)
|
||||
{
|
||||
printf("File:%s\n", fileName);
|
||||
// First the header.
|
||||
fread((uint8_t *)&mzfHeader, MZF_HEADER_SIZE, 1, ptr);
|
||||
printf("Load:%x\n", mzfHeader.loadAddr);
|
||||
if(mzfHeader.loadAddr > 0x1000)
|
||||
{
|
||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
||||
// Copy in the header.
|
||||
memcpy((uint8_t *)&Z80Ctrl->memory[MZ_CMT_ADDR], (uint8_t *)&mzfHeader, MZF_HEADER_SIZE);
|
||||
|
||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
||||
// Now read in the data.
|
||||
fread(&Z80Ctrl->memory[mzfHeader.loadAddr], mzfHeader.fileSize, 1, ptr);
|
||||
printf("Memcpy:%x,%x\n", mzfHeader.loadAddr, mzfHeader.fileSize);
|
||||
printf("Loaded %s, Size:%04x, Addr:%04x, Exec:%04x\n", fileName, mzfHeader.fileSize, mzfHeader.loadAddr, mzfHeader.execAddr);
|
||||
}
|
||||
|
||||
// Sync the loaded image from Virtual memory to hard memory.
|
||||
ioctlCmd.cmd = IOCTL_CMD_SYNC_TO_HOST_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Resume Z80 processing.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
else
|
||||
printf("Couldnt open file\n");
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Method to request basic Z80 operations.
|
||||
//
|
||||
int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long param3)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
uint32_t idx;
|
||||
int ret = 0;
|
||||
|
||||
switch(cmd)
|
||||
{
|
||||
case Z80_CMD_STOP:
|
||||
// Use IOCTL to request Z80 to Stop (power off) processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_START:
|
||||
// Use IOCTL to request Z80 to Start (power on) processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_PAUSE:
|
||||
// Use IOCTL to request Z80 to pause processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_PAUSE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_CONTINUE:
|
||||
// Use IOCTL to request Z80 continue processing.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CONTINUE;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_RESET:
|
||||
// Use IOCTL to request Z80 reset.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_SPEED:
|
||||
// Check value is in range.
|
||||
for(idx=1; idx < 256; idx+=idx)
|
||||
{
|
||||
if((uint32_t)param1 == idx) break;
|
||||
}
|
||||
if(idx == 256)
|
||||
{
|
||||
printf("Speed factor is illegal. It must be a multiple value of the original CPU clock, ie. 1x, 2x, 4x etc\n");
|
||||
ret = -1;
|
||||
} else
|
||||
{
|
||||
// Use IOCTL to request Z80 cpu freq change.
|
||||
ioctlCmd.speed.speedMultiplier = (uint32_t)param1;
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_CPU_FREQ;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case CPLD_CMD_SEND_CMD:
|
||||
// Build up the IOCTL command to request the given data is sent to the CPLD.
|
||||
ioctlCmd.cmd = IOCTL_CMD_CPLD_CMD;
|
||||
ioctlCmd.cpld.cmd = (uint32_t)param1;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_DUMP_MEMORY:
|
||||
// If virtual memory, we can dump it via the shared memory segment.
|
||||
if((uint8_t)param1)
|
||||
{
|
||||
memoryDump((uint32_t)param2, (uint32_t)param3, (uint8_t)param1, (uint8_t)param1 == 2 || (uint8_t)param1 == 3 ? 32 : 8, (uint32_t)param2, 0);
|
||||
} else
|
||||
{
|
||||
// Build an IOCTL command to get the driver to dump the memory.
|
||||
ioctlCmd.cmd = IOCTL_CMD_DUMP_MEMORY;
|
||||
ioctlCmd.addr.start = (uint32_t)param2;
|
||||
ioctlCmd.addr.end = (uint32_t)param2+(uint32_t)param3;
|
||||
ioctlCmd.addr.size = (uint32_t)param3;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
}
|
||||
break;
|
||||
case Z80_CMD_HOST_RAM:
|
||||
// Use IOCTL to request change to host RAM.
|
||||
ioctlCmd.cmd = IOCTL_CMD_USE_HOST_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_VIRTUAL_RAM:
|
||||
// Use IOCTL to request change to host RAM.
|
||||
ioctlCmd.cmd = IOCTL_CMD_USE_VIRTUAL_RAM;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case Z80_CMD_MEMORY_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_MEMTEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case CPLD_CMD_PRL_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_PRL_TEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
case CPLD_CMD_SPI_TEST:
|
||||
// Send command to test the SPI.
|
||||
ioctlCmd.cmd = IOCTL_CMD_SPI_TEST;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
default:
|
||||
printf("Command not supported!\n");
|
||||
ret = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Method to perform some simple tests on the Z80 emulator.
|
||||
//
|
||||
int z80test(int fdZ80)
|
||||
{
|
||||
// Locals.
|
||||
struct ioctlCmd ioctlCmd;
|
||||
int ret = 0;
|
||||
|
||||
// Stop the Z80.
|
||||
//
|
||||
printf("Send STOP\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
FILE *ptr;
|
||||
ptr = fopen("/customer/mz700.rom", "rb");
|
||||
if(ptr)
|
||||
{
|
||||
fread(&Z80Ctrl->memory, 65536, 1, ptr);
|
||||
} else printf("Couldnt open file\n");
|
||||
|
||||
// Configure the Z80.
|
||||
//
|
||||
printf("Send SETPC\n");
|
||||
ioctlCmd.z80.pc = 0;
|
||||
ioctl(fdZ80, IOCTL_CMD_SETPC, &ioctlCmd);
|
||||
|
||||
memoryDump(0 , 65536, 1, 8, 0, 0);
|
||||
|
||||
// Start the Z80.
|
||||
//
|
||||
printf("Send START\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
delay(10);
|
||||
|
||||
printf("Send STOP\n");
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
memoryDump(0, 65536, 1, 8, 0, 0);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Output usage screen. So mamy commands you do need to be prompted!!
|
||||
void showArgs(char *progName, struct optparse *options)
|
||||
{
|
||||
printf("%s %s %s %s\n\n", progName, VERSION, COPYRIGHT, AUTHOR);
|
||||
printf("Synopsis:\n");
|
||||
printf("%s --help # This help screen.\n", progName);
|
||||
printf(" --cmd <command> = RESET # Reset the Z80\n");
|
||||
printf(" = STOP # Stop and power off the Z80\n");
|
||||
printf(" = START # Power on and start the Z80\n");
|
||||
printf(" = PAUSE # Pause running Z80\n");
|
||||
printf(" = CONTINUE # Continue Z80 execution\n");
|
||||
printf(" = HOSTRAM # Use HOST DRAM\n");
|
||||
printf(" = VIRTRAM # Use Virtual RAM\n");
|
||||
printf(" = SPEED --speed <1, 2, 4, 8, 16, 32, 64, 128> # In Virtual RAM mode, set CPU speed to base clock x factor.\n");
|
||||
printf(" = LOADMZF --file <mzf filename> # Load MZF file into memory.\n");
|
||||
printf(" = DUMP --start <24bit addr> --end <24bit addr> --virtual <0 - Host RAM, 1 = Virtual RAM, 2 = PageTable, 3 = IOPageTable>\n");
|
||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
||||
printf(" = Z80TEST # Perform various debugging tests\n");
|
||||
printf(" = SPITEST # Perform SPI testing\n");
|
||||
printf(" = PRLTEST # Perform Parallel Bus testing\n");
|
||||
printf(" = Z80MEMTEST # Perform HOST memory tests.\n");
|
||||
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
int fdZ80;
|
||||
char buff[64];
|
||||
char cmd[64] = { 0 };
|
||||
char fileName[256] = { 0 };
|
||||
int opt;
|
||||
long hexData = 0;
|
||||
long speedMultiplier = 1;
|
||||
long startAddr = 0x0000;
|
||||
long endAddr = 0x1000;
|
||||
int virtualMemory = 0;
|
||||
int helpFlag = 0;
|
||||
int verboseFlag = 0;
|
||||
|
||||
// Define parameters to be processed.
|
||||
struct optparse options;
|
||||
static struct optparse_long long_options[] =
|
||||
{
|
||||
{"help", 'h', OPTPARSE_NONE},
|
||||
{"cmd", 'c', OPTPARSE_REQUIRED},
|
||||
{"file", 'f', OPTPARSE_REQUIRED},
|
||||
{"data", 'd', OPTPARSE_REQUIRED},
|
||||
{"speed", 'S', OPTPARSE_REQUIRED},
|
||||
{"virtual", 'V', OPTPARSE_REQUIRED},
|
||||
{"start", 's', OPTPARSE_REQUIRED},
|
||||
{"end", 'e', OPTPARSE_REQUIRED},
|
||||
{"verbose", 'v', OPTPARSE_NONE},
|
||||
{0}
|
||||
};
|
||||
|
||||
// Parse the command line options.
|
||||
//
|
||||
optparse_init(&options, argv);
|
||||
while((opt = optparse_long(&options, long_options, NULL)) != -1)
|
||||
{
|
||||
switch(opt)
|
||||
{
|
||||
// Hex data.
|
||||
case 'd':
|
||||
hexData = strtol(options.optarg, NULL, 0);
|
||||
//printf("Hex data:%08x\n", hexData);
|
||||
break;
|
||||
|
||||
// Start address for memory operations.
|
||||
case 's':
|
||||
startAddr = strtol(options.optarg, NULL, 0);
|
||||
//printf("Start Addr:%04x\n", startAddr);
|
||||
break;
|
||||
|
||||
// Speed multiplication factor for CPU governor when running in virtual memory.
|
||||
case 'S':
|
||||
speedMultiplier = strtol(options.optarg, NULL, 0);
|
||||
//printf("Speed = base freq x %d\n", speedFactor);
|
||||
break;
|
||||
|
||||
// End address for memory operations.
|
||||
case 'e':
|
||||
endAddr = strtol(options.optarg, NULL, 0);
|
||||
//printf("End Addr:%04x\n", endAddr);
|
||||
break;
|
||||
|
||||
// Virtual memory flag, 0 = host, 1 = virtual memory, 2 = page table, 3 = iopage table.
|
||||
case 'V':
|
||||
virtualMemory = atoi(options.optarg);
|
||||
break;
|
||||
|
||||
// Filename.
|
||||
case 'f':
|
||||
strcpy(fileName, options.optarg);
|
||||
break;
|
||||
|
||||
// Command to execute.
|
||||
case 'c':
|
||||
strcpy(cmd, options.optarg);
|
||||
break;
|
||||
|
||||
// Verbose mode.
|
||||
case 'v':
|
||||
verboseFlag = 1;
|
||||
break;
|
||||
|
||||
// Command help needed.
|
||||
case 'h':
|
||||
helpFlag = 1;
|
||||
showArgs(argv[0], &options);
|
||||
break;
|
||||
|
||||
// Unrecognised, show synopsis.
|
||||
case '?':
|
||||
showArgs(argv[0], &options);
|
||||
printf("%s: %s\n", argv[0], options.errmsg);
|
||||
return(1);
|
||||
}
|
||||
}
|
||||
|
||||
// Open the z80drv driver and attach to its shared memory, basically the Z80 control structure which includes the virtual Z80 memory.
|
||||
fdZ80 = open(DEVICE_FILENAME, O_RDWR|O_NDELAY);
|
||||
if(fdZ80 >= 0)
|
||||
{
|
||||
Z80Ctrl = (t_Z80Ctrl *)mmap(0, sizeof(t_Z80Ctrl), PROT_READ | PROT_WRITE, MAP_SHARED, fdZ80, 0);
|
||||
if(Z80Ctrl == (void *)-1)
|
||||
{
|
||||
printf("Failed to attach to the Z80 Control structure, cannot continue, exitting....\n");
|
||||
close(fdZ80);
|
||||
exit(1);
|
||||
}
|
||||
} else
|
||||
{
|
||||
printf("Failed to open the Z80 Driver, exitting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Basic string to method mapping. Started off with just 1 or two but has grown, may need a table!
|
||||
if(strcasecmp(cmd, "LOADMZF") == 0)
|
||||
{
|
||||
z80load(fdZ80, fileName);
|
||||
} else
|
||||
if(strcasecmp(cmd, "RESET") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_RESET, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "STOP") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_STOP, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "START") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_START, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "PAUSE") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_PAUSE, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "CONTINUE") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_CONTINUE, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "SPEED") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_SPEED, speedMultiplier, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "DUMP") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_DUMP_MEMORY, virtualMemory, startAddr, (endAddr - startAddr));
|
||||
} else
|
||||
if(strcasecmp(cmd, "HOSTRAM") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_HOST_RAM, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "VIRTRAM") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_VIRTUAL_RAM, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "CPLDCMD") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_SEND_CMD, hexData, 0, 0);
|
||||
} else
|
||||
|
||||
// Test methods, if the code is built-in to the driver.
|
||||
if(strcasecmp(cmd, "Z80TEST") == 0)
|
||||
{
|
||||
z80test(fdZ80);
|
||||
} else
|
||||
if(strcasecmp(cmd, "SPITEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_SPI_TEST, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "PRLTEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, CPLD_CMD_PRL_TEST, 0, 0, 0);
|
||||
} else
|
||||
if(strcasecmp(cmd, "Z80MEMTEST") == 0)
|
||||
{
|
||||
ctrlCmd(fdZ80, Z80_CMD_MEMORY_TEST, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
showArgs(argv[0], &options);
|
||||
printf("No command given, nothing done!\n");
|
||||
}
|
||||
|
||||
// Unmap shared memory and close the device.
|
||||
munmap(Z80Ctrl, sizeof(t_Z80Ctrl));
|
||||
close(fdZ80);
|
||||
|
||||
return(0);
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
284
software/FusionX/src/z80drv/MZ700/z80driver.h
vendored
284
software/FusionX/src/z80drv/MZ700/z80driver.h
vendored
@@ -1,284 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80driver.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Driver
|
||||
// This file contains the declarations used in the z80drv device driver.
|
||||
//
|
||||
// Credits: Zilog Z80 CPU Emulator v0.2 written by Manuel Sainz de Baranda y Goñi
|
||||
// The Z80 CPU Emulator is the heart of this driver and in all ways, is compatible with
|
||||
// the original Z80.
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
// (c) 1999-2022 Manuel Sainz de Baranda y Goñi
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80DRIVER_H
|
||||
#define Z80DRIVER_H
|
||||
|
||||
// Constants.
|
||||
#define Z80_VIRTUAL_ROM_SIZE 16384 // Sized to maximum ROM which is the MZ-800 ROM.
|
||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 8) // (PAGE_SIZE * 2) // max size mmaped to userspace
|
||||
#define Z80_VIRTUAL_MEMORY_SIZE Z80_VIRTUAL_RAM_SIZE + Z80_VIRTUAL_ROM_SIZE
|
||||
#define Z80_MEMORY_PAGE_SIZE 16
|
||||
#define MAX_SCREEN_WIDTH 132
|
||||
#define DEVICE_NAME "z80drv"
|
||||
#define CLASS_NAME "mogu"
|
||||
|
||||
// Memory and IO page types. Used to create a memory page which maps type of address space to real address space on host or virtual memory.
|
||||
#define MEMORY_TYPE_VIRTUAL_MASK 0x00FFFFFF
|
||||
#define MEMORY_TYPE_REAL_MASK 0x0000FFFF
|
||||
#define IO_TYPE_MASK 0x0000FFFF
|
||||
#define MEMORY_TYPE_INHIBIT 0x00000000
|
||||
#define MEMORY_TYPE_PHYSICAL_RAM 0x80000000
|
||||
#define MEMORY_TYPE_PHYSICAL_ROM 0x40000000
|
||||
#define MEMORY_TYPE_PHYSICAL_VRAM 0x20000000
|
||||
#define MEMORY_TYPE_PHYSICAL_HW 0x10000000
|
||||
#define MEMORY_TYPE_VIRTUAL_RAM 0x08000000
|
||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
||||
#define MEMORY_TYPE_VIRTUAL_HW 0x02000000
|
||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
||||
|
||||
|
||||
// Approximate governor delays to regulate emulated CPU speed.
|
||||
#define MZ700_INSTRUCTION_DELAY_3_54MHZ 253
|
||||
#define MZ700_INSTRUCTION_DELAY_7MHZ 126
|
||||
#define MZ700_INSTRUCTION_DELAY_14MHZ 63
|
||||
#define MZ700_INSTRUCTION_DELAY_28MHZ 32
|
||||
#define MZ700_INSTRUCTION_DELAY_56MHZ 16
|
||||
#define MZ700_INSTRUCTION_DELAY_112MHZ 8
|
||||
#define MZ700_INSTRUCTION_DELAY_224MHZ 4
|
||||
#define MZ700_INSTRUCTION_DELAY_448MHZ 1
|
||||
|
||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||
#define IOCTL_CMD_Z80_STOP 's'
|
||||
#define IOCTL_CMD_Z80_START 'S'
|
||||
#define IOCTL_CMD_Z80_PAUSE 'P'
|
||||
#define IOCTL_CMD_Z80_RESET 'R'
|
||||
#define IOCTL_CMD_Z80_CONTINUE 'C'
|
||||
#define IOCTL_CMD_USE_HOST_RAM 'x'
|
||||
#define IOCTL_CMD_USE_VIRTUAL_RAM 'X'
|
||||
#define IOCTL_CMD_DUMP_MEMORY 'M'
|
||||
#define IOCTL_CMD_Z80_CPU_FREQ 'F'
|
||||
#define IOCTL_CMD_CPLD_CMD 'z'
|
||||
#define IOCTL_CMD_SEND _IOW('c', 'c', int32_t *)
|
||||
#define IOCTL_CMD_SETPC _IOW('p', 'p', int32_t *)
|
||||
#define IOCTL_CMD_SYNC_TO_HOST_RAM 'V'
|
||||
#define IOCTL_CMD_SPI_TEST '1'
|
||||
#define IOCTL_CMD_PRL_TEST '2'
|
||||
#define IOCTL_CMD_Z80_MEMTEST '3'
|
||||
|
||||
|
||||
|
||||
// Chip Select map MZ80K-MZ700.
|
||||
//
|
||||
// 0000 - 0FFF = CS_ROMni : R/W : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||
// 1000 - CFFF = CS_RAMni : R/W : MZ80K/A/700 = RAM
|
||||
// C000 - CFFF = CS_ROMni : R/W : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||
// D000 - D7FF = CS_VRAMni : R/W : MZ80K/A/700 = VRAM
|
||||
// D800 - DFFF = CS_VRAMni : R/W : MZ700 = Colour VRAM (MZ700)
|
||||
// E000 - E003 = CS_8255n : R/W : MZ80K/A/700 = 8255
|
||||
// E004 - E007 = CS_8254n : R/W : MZ80K/A/700 = 8254
|
||||
// E008 - E00B = CS_LS367n : R/W : MZ80K/A/700 = LS367
|
||||
// E00C - E00F = CS_ESWPn : R : MZ80A = Memory Swap (MZ80A)
|
||||
// E010 - E013 = CS_ESWPn : R : MZ80A = Reset Memory Swap (MZ80A)
|
||||
// E014 = CS_E5n : R/W : MZ80A/700 = Normal CRT display (in Video Controller)
|
||||
// E015 = CS_E6n : R/W : MZ80A/700 = Reverse CRT display (in Video Controller)
|
||||
// E200 - E2FF = : R/W : MZ80A/700 = VRAM roll up/roll down.
|
||||
// E800 - EFFF = : R/W : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||
// F000 - F7FF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
||||
// F800 - FFFF = : R/W : MZ80K/A/700 = Floppy Disk interface.
|
||||
//
|
||||
// Chip Select map MZ800
|
||||
//
|
||||
// FC - FF = CS_PIOn : R/W : MZ800/MZ1500 = Z80 PIO Printer Interface
|
||||
// F2 = CS_PSG0n : W : MZ800/MZ1500 = Programable Sound Generator, MZ-800 = Mono, MZ-1500 = Left Channel
|
||||
// F3 = CS_PSG1n : W : MZ1500 = Programable Sound Generator, MZ-1500 = Right Channel
|
||||
// E9 = CS_PSG(X)n: W : MZ1500 = Simultaneous write to both PSG's.
|
||||
// F0 - F1 = CS_JOYSTK : R : MZ800 = Joystick 1 and 2
|
||||
// CC = CS_GWF : W : MZ800 = CRTC GWF Write format Register
|
||||
// CD = CS_GRF : W : MZ800 = CRTC GRF Read format Register
|
||||
// CE = CS_GDMD : W : MZ800 = CRTC GDMD Mode Register
|
||||
// CF = CS_GCRTC : W : MZ800 = CRTC GCRTC Control Register
|
||||
// D4 - D7 = CS
|
||||
// D000 - DFFF
|
||||
|
||||
// MZ700/MZ800 memory mode switch?
|
||||
//
|
||||
// MZ-700 MZ-800
|
||||
// |0000:0FFF|1000:1FFF|1000:CFFF|C000:CFFF|D000:FFFF |0000:7FFF|1000:1FFF|2000:7FFF|8000:BFFF|C000:CFFF|C000:DFFF|E000:FFFF
|
||||
// -------------------------------------------------- ----------------------------------------------------------------------
|
||||
// OUT 0xE0 = |DRAM | | | | |DRAM | | | | | |
|
||||
// OUT 0xE1 = | | | | |DRAM | | | | | | |DRAM
|
||||
// OUT 0xE2 = |MONITOR | | | | |MONITOR | | | | | |
|
||||
// OUT 0xE3 = | | | | |Memory Mapped I/O | | | | | | |Upper MONITOR ROM
|
||||
// OUT 0xE4 = |MONITOR | |DRAM | |Memory Mapped I/O |MONITOR |CGROM |DRAM |VRAM | |DRAM |Upper MONITOR ROM
|
||||
// OUT 0xE5 = | | | | |Inhibit | | | | | | |Inhibit
|
||||
// OUT 0xE6 = | | | | |<return> | | | | | | |<return>
|
||||
// IN 0xE0 = | |CGROM* | |VRAM* | | |CGROM | |VRAM | | |
|
||||
// IN 0xE1 = | |DRAM | |DRAM | | |<return> | |DRAM | | |
|
||||
//
|
||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||
// * = MZ-800 host only.
|
||||
|
||||
// Macros to lookup and test to see if a given memory block or IO byte is of a given type. Also macros to read/write to the memory block and IO byte.
|
||||
#define MEMORY_BLOCK_GRANULARITY 0x800
|
||||
#define MEMORY_BLOCK_SLOTS (0x10000 / MEMORY_BLOCK_GRANULARITY)
|
||||
#define MEMORY_BLOCK_MASK (0x10000 - MEMORY_BLOCK_GRANULARITY)
|
||||
#define MEMORY_BLOCK_SHIFT 11
|
||||
#define getPageData(a) (Z80Ctrl->page[(a & 0xF800) >> MEMORY_BLOCK_SHIFT])
|
||||
#define getIOPageData(a) (Z80Ctrl->iopage[(a & 0xFFFF])
|
||||
#define getPageType(a, mask) (getPageData(a) & mask)
|
||||
#define getPageAddr(a, mask) ((getPageData(a) & mask) + (a & (MEMORY_BLOCK_GRANULARITY-1)))
|
||||
#define getIOPageType(a, mask) (getIOPageData(a) & mask)
|
||||
#define getIOPageAddr(a, mask) (getIOPageData(a) & mask)
|
||||
#define realAddress(a) (Z80Ctrl->page[getPageAddr(a, MEMORY_TYPE_REAL_MASK)])
|
||||
#define realPort(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_MASK)
|
||||
#define isPhysicalRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_RAM))
|
||||
#define isPhysicalVRAM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_VRAM))
|
||||
#define isPhysicalROM(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_ROM))
|
||||
#define isPhysicalMemory(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM))])
|
||||
#define isPhysicalHW(a) (getPageType(a, MEMORY_TYPE_PHYSICAL_HW))
|
||||
#define isPhysical(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_PHYSICAL_ROM | MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_PHYSICAL_VRAM)))
|
||||
#define isPhysicalIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_PHYSICAL_HW)
|
||||
#define isVirtualRAM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_RAM))
|
||||
#define isVirtualROM(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_ROM))
|
||||
#define isVirtualMemory(a) (getPageType(a, (MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_RAM)))
|
||||
#define isVirtualHW(a) (getPageType(a, MEMORY_TYPE_VIRTUAL_HW))
|
||||
#define isVirtualIO(a) (Z80Ctrl->iopage[a & 0xFFFF] & IO_TYPE_VIRTUAL_HW)
|
||||
#define isHW(a) (getPageType(a, (MEMORY_TYPE_PHYSICAL_HW | MEMORY_TYPE_VIRTUAL_HW)))
|
||||
#define readVirtualRAM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ])
|
||||
#define readVirtualROM(a) (Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) + Z80_VIRTUAL_RAM_SIZE ])
|
||||
#define writeVirtualRAM(a, d) { Z80Ctrl->memory[ getPageAddr(a, MEMORY_TYPE_VIRTUAL_MASK) ] = d; }
|
||||
#define setMemoryType(_block_,_type_,_addr_) { Z80Ctrl->page[_block_] = _type_ | _addr_; }
|
||||
#define backupMemoryType(_block_) { Z80Ctrl->shadowPage[_block_] = Z80Ctrl->page[_block_]; }
|
||||
#define restoreMemoryType(_block_) { Z80Ctrl->page[_block_] = Z80Ctrl->shadowPage[_block_]; }
|
||||
|
||||
#define IO_ADDR_E0 0xE0
|
||||
#define IO_ADDR_E1 0xE1
|
||||
#define IO_ADDR_E2 0xE2
|
||||
#define IO_ADDR_E3 0xE3
|
||||
#define IO_ADDR_E4 0xE4
|
||||
#define IO_ADDR_E5 0xE5
|
||||
#define IO_ADDR_E6 0xE6
|
||||
#define IO_ADDR_E7 0xE7
|
||||
|
||||
|
||||
enum Z80_RUN_STATES {
|
||||
Z80_STOP = 0x00,
|
||||
Z80_STOPPED = 0x01,
|
||||
Z80_PAUSE = 0x02,
|
||||
Z80_PAUSED = 0x03,
|
||||
Z80_CONTINUE = 0x04,
|
||||
Z80_RUNNING = 0x05,
|
||||
};
|
||||
enum Z80_MEMORY_PROFILE {
|
||||
USE_PHYSICAL_RAM = 0x00,
|
||||
USE_VIRTUAL_RAM = 0x01
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// Main memory, linear but indexed as though it were banks in 1K pages.
|
||||
uint8_t memory[Z80_VIRTUAL_MEMORY_SIZE];
|
||||
|
||||
// Page pointer map.
|
||||
//
|
||||
// Each pointer points to a byte or block of bytes in the Z80 Memory frame, 64K Real + Banked.
|
||||
// This is currently set at a block of size 0x800 per memory pointer for the MZ-700.
|
||||
// The LSB of the pointer is a direct memory index to a byte or block of bytes, the upper byte of the pointer indicates type of memory space.
|
||||
// 0x80<FFFFFF> - physical host RAM
|
||||
// 0x40<FFFFFF> - physical host ROM
|
||||
// 0x20<FFFFFF> - physical host VRAM
|
||||
// 0x10<FFFFFF> - physical host hardware
|
||||
// 0x08<FFFFFF> - virtual host RAM
|
||||
// 0x04<FFFFFF> - virtual host ROM
|
||||
// 0x02<FFFFFF> - virtual host hardware
|
||||
// 16bit Input Address -> map -> Pointer to 24bit memory address + type flag.
|
||||
// -> Pointer+<low bits of address> to 24bit memory address + type flag.
|
||||
uint32_t page[MEMORY_BLOCK_SLOTS];
|
||||
uint32_t shadowPage[MEMORY_BLOCK_SLOTS];
|
||||
|
||||
// I/O Page map.
|
||||
//
|
||||
// This is a map to indicate the use of the I/O page and allow any required remapping.
|
||||
// <0x80>FF<I/O Address> - physical host hardware
|
||||
// <0x40>FF<I/O Address> - virtual host hardware
|
||||
// 16bit Input Address -> map -> Actual 16bit address to use + type flag.
|
||||
uint32_t iopage[65536];
|
||||
|
||||
// Default page mode configured. This value reflects the default page and iotable map.
|
||||
uint8_t defaultPageMode;
|
||||
|
||||
// Refresh DRAM mode. 1 = Refresh, 0 = No refresh. Only applicable when running code in virtual Kernel RAM.
|
||||
uint8_t refreshDRAM;
|
||||
|
||||
// Inhibit mode is where certain memory ranges are inhibitted. The memory page is set to inhibit and this flag
|
||||
// blocks actions which arent allowed during inhibit.
|
||||
uint8_t inhibitMode;
|
||||
|
||||
// Address caching. Used to minimise instruction length sent to CPLD.
|
||||
uint16_t z80PrevAddr;
|
||||
uint16_t z80PrevPort;
|
||||
|
||||
// Keyboard strobe and data. Required to detect hotkey press.
|
||||
uint8_t keyportStrobe;
|
||||
uint8_t keyportShiftCtrl;
|
||||
uint8_t keyportHotKey;
|
||||
|
||||
// Governor is the delay in a 32bit loop per Z80 opcode, used to govern execution speed when using virtual memory.
|
||||
// This mechanism will eventually be tied into the M/T-state calculation for a more precise delay, but at the moment,
|
||||
// with the Z80 assigned to an isolated CPU, it allows time sensitive tasks such as the tape recorder to work.
|
||||
// The lower the value the faster the CPU speed.
|
||||
uint32_t cpuGovernorDelay;
|
||||
} t_Z80Ctrl;
|
||||
|
||||
// IOCTL structure for passing data from user space to driver to perform commands.
|
||||
//
|
||||
struct z80_addr {
|
||||
uint32_t start;
|
||||
uint32_t end;
|
||||
uint32_t size;
|
||||
};
|
||||
struct z80_ctrl {
|
||||
uint16_t pc;
|
||||
};
|
||||
struct speed {
|
||||
uint32_t speedMultiplier;
|
||||
};
|
||||
struct cpld_ctrl {
|
||||
uint32_t cmd;
|
||||
};
|
||||
struct ioctlCmd {
|
||||
int32_t cmd;
|
||||
union {
|
||||
struct z80_addr addr;
|
||||
struct z80_ctrl z80;
|
||||
struct speed speed;
|
||||
struct cpld_ctrl cpld;
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
// Prototypes.
|
||||
void setupMemory(enum Z80_MEMORY_PROFILE mode);
|
||||
|
||||
|
||||
#endif
|
||||
@@ -1,428 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface
|
||||
// This file contains the methods used in interfacing the SOM to the Z80 socket
|
||||
// and host hardware via a CPLD.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
//#include <stdio.h>
|
||||
//#include <stdlib.h>
|
||||
//#include <string.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
// User space driver access.
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// Initialise the SOM hardware used to communicate with the z80 socket and host hardware.
|
||||
// The SOM interfaces to a CPLD which provides voltage level translation and also encapsulates the Z80 timing cycles as recreating
|
||||
// them within the SOM is much more tricky.
|
||||
//
|
||||
// As this is an embedded device and performance/latency are priorities, minimal structured code is used to keep call stack and
|
||||
// generated code to a mimimum without relying on the optimiser.
|
||||
int z80io_init(void)
|
||||
{
|
||||
// Locals.
|
||||
int ret = 0;
|
||||
|
||||
// Initialise GPIO. We call the HAL api to minimise time but for actual bit set/reset and read we go directly to registers to save time, increase throughput and minimise latency.
|
||||
// Initialise the HAL.
|
||||
MHal_GPIO_Init();
|
||||
|
||||
// Set the pads as GPIO devices. The HAL takes care of allocating and deallocating the padmux resources.
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_0); // Word (16bit) bidirectional bus. Default is read with data set.
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_1);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_2);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_3);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_4);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_5);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_6);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_IN_DATA_7);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_HIGH_BYTE);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO8); // SPIO 4wire control lines setup by the spidev driver but controlled directly in this driver.
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO9);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO10);
|
||||
//MHal_GPIO_Pad_Set(PAD_GPIO11);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_READY);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_LTSTATE);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSRQ);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_BUSACK);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_INT);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_NMI);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WAIT);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RESET);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_RSV1);
|
||||
#ifdef NOTNEEDED
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_0);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_1);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_2);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_3);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_4);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_5);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_6);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_OUT_DATA_7);
|
||||
MHal_GPIO_Pad_Set(PAD_Z80IO_WRITE);
|
||||
#endif
|
||||
|
||||
// Set required input pads.
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_0);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_1);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_2);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_3);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_4);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_5);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_6);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_IN_DATA_7);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_READY);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_LTSTATE);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSRQ);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_BUSACK);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_INT);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_NMI);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_WAIT);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RESET);
|
||||
MHal_GPIO_Pad_Odn(PAD_Z80IO_RSV1);
|
||||
|
||||
// Set required output pads.
|
||||
#ifdef NOTNEEDED
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_0);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_1);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_2);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_3);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_4);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_5);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_6);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_OUT_DATA_7);
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_WRITE);
|
||||
MHal_GPIO_Pull_High(PAD_Z80IO_WRITE);
|
||||
#endif
|
||||
|
||||
// Control signals.
|
||||
MHal_GPIO_Pad_Oen(PAD_Z80IO_HIGH_BYTE);
|
||||
MHal_GPIO_Pull_High(PAD_Z80IO_HIGH_BYTE);
|
||||
|
||||
// Setup the MSPI0 device.
|
||||
//
|
||||
// Setup control, interrupts are not used.
|
||||
MSPI_WRITE(MSPI_CTRL_OFFSET, MSPI_CPU_CLOCK_1_2 | MSPI_CTRL_CPOL_LOW | MSPI_CTRL_CPHA_HIGH | MSPI_CTRL_RESET | MSPI_CTRL_ENABLE_SPI);
|
||||
|
||||
// Setup LSB First mode.
|
||||
MSPI_WRITE(MSPI_LSB_FIRST_OFFSET, 0x0);
|
||||
|
||||
// Setup clock.
|
||||
CLK_WRITE(MSPI0_CLK_CFG, 0x1100)
|
||||
|
||||
// Setup the frame size (all buffers to 8bits).
|
||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_WBIT_OFFSET+1, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET, 0xfff);
|
||||
MSPI_WRITE(MSPI_FRAME_RBIT_OFFSET+1, 0xfff);
|
||||
|
||||
// Setup Chip Selects to inactive.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Switch Video and Audio to host.
|
||||
z80io_SPI_Send16(0x00f0, NULL);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Parallel bus Methods.
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Methods to read data from the parallel bus.
|
||||
// The CPLD returns status and Z80 data on the 8bit bus as it is marginally quicker than retrieving it over the SPI bus.
|
||||
//
|
||||
inline uint8_t z80io_PRL_Read8(uint8_t dataFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
|
||||
// Byte according to flag.
|
||||
if(dataFlag)
|
||||
SET_CPLD_READ_DATA()
|
||||
else
|
||||
SET_CPLD_READ_STATUS()
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result = READ_CPLD_DATA_IN();
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
inline uint16_t z80io_PRL_Read16(void)
|
||||
{
|
||||
// Locals.
|
||||
uint16_t result = 0;
|
||||
|
||||
// Low byte first.
|
||||
CLEAR_CPLD_HIGH_BYTE();
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result = (uint16_t)READ_CPLD_DATA_IN();
|
||||
|
||||
// High byte next.
|
||||
SET_CPLD_HIGH_BYTE();
|
||||
|
||||
// Read the input registers and set value accordingly.
|
||||
result |= (uint16_t)(READ_CPLD_DATA_IN() << 8);
|
||||
|
||||
// Return 16bit value read from CPLD.
|
||||
return(result);
|
||||
}
|
||||
|
||||
|
||||
// Parallel Bus methods were tried and tested but due to the GPIO bits being controlled by individual registers per bit, the setup time was longer
|
||||
// than the transmission time of SPI. These methods are thus deprecated and a fusion of SPI and 8bit parallel is now used.
|
||||
#ifdef NOTNEEDED
|
||||
inline uint8_t z80io_PRL_Send8(uint8_t txData)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
|
||||
// Low byte only.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
||||
|
||||
// Setup data.
|
||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
inline uint8_t z80io_PRL_Send16(uint16_t txData)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
|
||||
// Low byte first.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE].r_out) &= (~gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out);
|
||||
|
||||
// Setup data.
|
||||
if(txData & 0x0080) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x0040) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x0020) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x0010) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0008) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0004) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0002) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0001) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
// High byte next.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
|
||||
// Setup high byte.
|
||||
if(txData & 0x8000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_7].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_7].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_7].m_out); }
|
||||
if(txData & 0x4000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_6].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_6].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_6].m_out); }
|
||||
if(txData & 0x2000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_5].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_5].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_5].m_out); }
|
||||
if(txData & 0x1000) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_4].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_4].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_4].m_out); }
|
||||
if(txData & 0x0800) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_3].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_3].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_3].m_out); }
|
||||
if(txData & 0x0400) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_2].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_2].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_2].m_out); }
|
||||
if(txData & 0x0200) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_1].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_1].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_1].m_out); }
|
||||
if(txData & 0x0100) { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) |= gpio_table[PAD_Z80IO_OUT_DATA_0].m_out; } else { MHal_RIU_REG(gpio_table[PAD_Z80IO_OUT_DATA_0].r_out) &= (~gpio_table[PAD_Z80IO_OUT_DATA_0].m_out); }
|
||||
|
||||
// Clock data.
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) &= (~gpio_table[PAD_Z80IO_WRITE ].m_out);
|
||||
MHal_RIU_REG(gpio_table[PAD_Z80IO_WRITE].r_out) |= gpio_table[PAD_Z80IO_WRITE ].m_out;
|
||||
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
//--------------------------------------------------------
|
||||
// SPI Methods.
|
||||
//--------------------------------------------------------
|
||||
|
||||
// Methods to send 8,16 or 32 bits. Each method is seperate to minimise logic and execution time, 8bit being most sensitive.
|
||||
// Macros have also been defined for inline inclusion which dont read back the response data.
|
||||
//
|
||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = (uint8_t)MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, txData);
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = MSPI_READ(MSPI_FULL_DEPLUX_RD00);
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t timeout = MAX_CHECK_CNT;
|
||||
|
||||
// Insert data into write buffers.
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)txData);
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)(txData >> 16));
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4);
|
||||
|
||||
// Enable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE);
|
||||
|
||||
// Send.
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER);
|
||||
|
||||
// Wait for completion.
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0)
|
||||
{
|
||||
if(--timeout == 0)
|
||||
break;
|
||||
}
|
||||
|
||||
// Disable SPI select.
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE);
|
||||
|
||||
// Clear flag.
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);
|
||||
|
||||
// Fetch data.
|
||||
if(rxData != NULL) *rxData = (uint32_t)(MSPI_READ(MSPI_FULL_DEPLUX_RD00) | (MSPI_READ(MSPI_FULL_DEPLUX_RD02) << 16));
|
||||
|
||||
// Done.
|
||||
return(timeout == 0);
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
#ifdef INCLUDE_TEST_METHODS
|
||||
#include "z80io_test.c"
|
||||
#else
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
{
|
||||
pr_info("Z80 Test Memory functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
uint8_t z80io_SPI_Test(void)
|
||||
{
|
||||
pr_info("SPI Test functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
uint8_t z80io_PRL_Test(void)
|
||||
{
|
||||
pr_info("Parallel Bus Test functionality not built-in.\n");
|
||||
return(0);
|
||||
}
|
||||
#endif
|
||||
483
software/FusionX/src/z80drv/MZ700/z80io.h
vendored
483
software/FusionX/src/z80drv/MZ700/z80io.h
vendored
@@ -1,483 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface
|
||||
// This file contains the declarations used in interfacing the SOM to the Z80 socket
|
||||
// and host hardware via a CPLD.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80IO_H
|
||||
#define Z80IO_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Definitions to control compilation.
|
||||
#define INCLUDE_TEST_METHODS 1
|
||||
|
||||
// CPLD Commands.
|
||||
#define CPLD_CMD_FETCH_ADDR 0x10
|
||||
#define CPLD_CMD_FETCH_ADDR_P1 0x11
|
||||
#define CPLD_CMD_FETCH_ADDR_P2 0x12
|
||||
#define CPLD_CMD_FETCH_ADDR_P3 0x13
|
||||
#define CPLD_CMD_FETCH_ADDR_P4 0x14
|
||||
#define CPLD_CMD_FETCH_ADDR_P5 0x15
|
||||
#define CPLD_CMD_FETCH_ADDR_P6 0x16
|
||||
#define CPLD_CMD_FETCH_ADDR_P7 0x17
|
||||
#define CPLD_CMD_WRITE_ADDR 0x18
|
||||
#define CPLD_CMD_WRITE_ADDR_P1 0x19
|
||||
#define CPLD_CMD_WRITE_ADDR_P2 0x1A
|
||||
#define CPLD_CMD_WRITE_ADDR_P3 0x1B
|
||||
#define CPLD_CMD_WRITE_ADDR_P4 0x1C
|
||||
#define CPLD_CMD_WRITE_ADDR_P5 0x1D
|
||||
#define CPLD_CMD_WRITE_ADDR_P6 0x1E
|
||||
#define CPLD_CMD_WRITE_ADDR_P7 0x1F
|
||||
#define CPLD_CMD_READ_ADDR 0x20
|
||||
#define CPLD_CMD_READ_ADDR_P1 0x21
|
||||
#define CPLD_CMD_READ_ADDR_P2 0x22
|
||||
#define CPLD_CMD_READ_ADDR_P3 0x23
|
||||
#define CPLD_CMD_READ_ADDR_P4 0x24
|
||||
#define CPLD_CMD_READ_ADDR_P5 0x25
|
||||
#define CPLD_CMD_READ_ADDR_P6 0x26
|
||||
#define CPLD_CMD_READ_ADDR_P7 0x27
|
||||
#define CPLD_CMD_WRITEIO_ADDR 0x28
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P1 0x29
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P2 0x2A
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P3 0x2B
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P4 0x2C
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P5 0x2D
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P6 0x2E
|
||||
#define CPLD_CMD_WRITEIO_ADDR_P7 0x2F
|
||||
#define CPLD_CMD_READIO_ADDR 0x30
|
||||
#define CPLD_CMD_READIO_ADDR_P1 0x31
|
||||
#define CPLD_CMD_READIO_ADDR_P2 0x32
|
||||
#define CPLD_CMD_READIO_ADDR_P3 0x33
|
||||
#define CPLD_CMD_READIO_ADDR_P4 0x34
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||
#define CPLD_CMD_HALT 0x50
|
||||
#define CPLD_CMD_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
#define CPLD_CMD_SET_AUTO_REFRESH 0xF1
|
||||
#define CPLD_CMD_CLEAR_AUTO_REFRESH 0xF2
|
||||
#define CPLD_CMD_SET_SPI_LOOPBACK 0xFE
|
||||
#define CPLD_CMD_NOP1 0x00
|
||||
#define CPLD_CMD_NOP2 0xFF
|
||||
|
||||
|
||||
// Pad numbers for using the MHal GPIO library.
|
||||
#define PAD_Z80IO_IN_DATA_0 PAD_GPIO0
|
||||
#define PAD_Z80IO_IN_DATA_1 PAD_GPIO1
|
||||
#define PAD_Z80IO_IN_DATA_2 PAD_GPIO2
|
||||
#define PAD_Z80IO_IN_DATA_3 PAD_GPIO3
|
||||
#define PAD_Z80IO_IN_DATA_4 PAD_GPIO4
|
||||
#define PAD_Z80IO_IN_DATA_5 PAD_GPIO5
|
||||
#define PAD_Z80IO_IN_DATA_6 PAD_GPIO6
|
||||
#define PAD_Z80IO_IN_DATA_7 PAD_GPIO7
|
||||
#define PAD_SPIO_0 PAD_GPIO8
|
||||
#define PAD_SPIO_1 PAD_GPIO9
|
||||
#define PAD_SPIO_2 PAD_GPIO10
|
||||
#define PAD_SPIO_3 PAD_GPIO11
|
||||
#define PAD_Z80IO_HIGH_BYTE PAD_SAR_GPIO2 // Byte requiured, 0 = Low Byte, 1 = High Byte.
|
||||
#define PAD_Z80IO_READY PAD_GPIO12
|
||||
#define PAD_Z80IO_LTSTATE PAD_PM_IRIN // IRIN
|
||||
#define PAD_Z80IO_BUSRQ PAD_GPIO13
|
||||
#define PAD_Z80IO_BUSACK PAD_GPIO14
|
||||
#define PAD_Z80IO_INT PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_NMI PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_WAIT PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_RESET PAD_VSYNC_OUT // GPIO86
|
||||
#define PAD_Z80IO_RSV1 PAD_SATA_GPIO // GPIO90
|
||||
|
||||
// Physical register addresses.
|
||||
#define PAD_Z80IO_IN_DATA_0_ADDR 0x103C00
|
||||
#define PAD_Z80IO_IN_DATA_1_ADDR 0x103C02
|
||||
#define PAD_Z80IO_IN_DATA_2_ADDR 0x103C04
|
||||
#define PAD_Z80IO_IN_DATA_3_ADDR 0x103C06
|
||||
#define PAD_Z80IO_IN_DATA_4_ADDR 0x103C08
|
||||
#define PAD_Z80IO_IN_DATA_5_ADDR 0x103C0A
|
||||
#define PAD_Z80IO_IN_DATA_6_ADDR 0x103C0C
|
||||
#define PAD_Z80IO_IN_DATA_7_ADDR 0x103C0E
|
||||
#define PAD_SPIO_0_ADDR 0x103C10
|
||||
#define PAD_SPIO_1_ADDR 0x103C12
|
||||
#define PAD_SPIO_2_ADDR 0x103C14
|
||||
#define PAD_SPIO_3_ADDR 0x103C16
|
||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
||||
#define PAD_Z80IO_LTSTATE_ADDR 0xF28 // IRIN
|
||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||
#define PAD_Z80IO_INT_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_NMI_ADDR 0x103C32 // GPIO48
|
||||
#define PAD_Z80IO_WAIT_ADDR 0x103C80 // GPIO85
|
||||
#define PAD_Z80IO_RESET_ADDR 0x103C82 // GPIO86
|
||||
#define PAD_Z80IO_RSV1_ADDR 0x103C8A // GPIO90
|
||||
|
||||
#ifdef NOTNEEDED
|
||||
#define PAD_Z80IO_OUT_DATA_0 PAD_GPIO12
|
||||
#define PAD_Z80IO_OUT_DATA_1 PAD_GPIO13
|
||||
#define PAD_Z80IO_OUT_DATA_2 PAD_GPIO14
|
||||
#define PAD_Z80IO_OUT_DATA_3 PAD_UART0_RX // GPIO47
|
||||
#define PAD_Z80IO_OUT_DATA_4 PAD_UART0_TX // GPIO48
|
||||
#define PAD_Z80IO_OUT_DATA_5 PAD_HSYNC_OUT // GPIO85
|
||||
#define PAD_Z80IO_OUT_DATA_6 PAD_VSYNC_OUT // GPIO86
|
||||
#define PAD_Z80IO_OUT_DATA_7 PAD_SATA_GPIO // GPIO90
|
||||
#define PAD_Z80IO_WRITE PAD_PM_IRIN // Write data clock.
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// The definitions below come from SigmaStar kernel drivers. No header file exists hence the
|
||||
// duplication.
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
#define SUPPORT_SPI_1 0
|
||||
#define MAX_SUPPORT_BITS 16
|
||||
|
||||
#define BANK_TO_ADDR32(b) (b<<9)
|
||||
#define BANK_SIZE 0x200
|
||||
|
||||
#define MS_BASE_REG_RIU_PA 0x1F000000
|
||||
#define gChipBaseAddr 0xFD203C00
|
||||
#define gPmSleepBaseAddr 0xFD001C00
|
||||
#define gSarBaseAddr 0xFD002800
|
||||
#define gRIUBaseAddr 0xFD000000
|
||||
#define gMOVDMAAddr 0xFD201600
|
||||
#define gClkBaseAddr 0xFD207000
|
||||
#define gMspBaseAddr 0xfd222000
|
||||
|
||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
|
||||
|
||||
#define MSPI0_BANK_ADDR 0x1110
|
||||
#define MSPI1_BANK_ADDR 0x1111
|
||||
#define CLK__BANK_ADDR 0x1038
|
||||
#define CHIPTOP_BANK_ADDR 0x101E
|
||||
#define MOVDMA_BANK_ADDR 0x100B
|
||||
|
||||
#define BASE_REG_MSPI0_ADDR MSPI0_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111000)
|
||||
#define BASE_REG_MSPI1_ADDR MSPI1_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x111100)
|
||||
#define BASE_REG_CLK_ADDR CLK__BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x103800)
|
||||
#define BASE_REG_CHIPTOP_ADDR CHIPTOP_BANK_ADDR*0x200 //GET_BASE_ADDR_BY_BANK(IO_ADDRESS(MS_BASE_REG_RIU_PA), 0x101E00)
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Hardware Register Capability
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
#define MSPI_WRITE_BUF_OFFSET 0x40
|
||||
#define MSPI_READ_BUF_OFFSET 0x44
|
||||
#define MSPI_WBF_SIZE_OFFSET 0x48
|
||||
#define MSPI_RBF_SIZE_OFFSET 0x48
|
||||
// read/ write buffer size
|
||||
#define MSPI_RWSIZE_MASK 0xFF
|
||||
#define MSPI_RSIZE_BIT_OFFSET 0x8
|
||||
#define MAX_READ_BUF_SIZE 0x8
|
||||
#define MAX_WRITE_BUF_SIZE 0x8
|
||||
// CLK config
|
||||
#define MSPI_CTRL_OFFSET 0x49
|
||||
#define MSPI_CLK_CLOCK_OFFSET 0x49
|
||||
#define MSPI_CLK_CLOCK_BIT_OFFSET 0x08
|
||||
#define MSPI_CLK_CLOCK_MASK 0xFF
|
||||
#define MSPI_CLK_PHASE_MASK 0x40
|
||||
#define MSPI_CLK_PHASE_BIT_OFFSET 0x06
|
||||
#define MSPI_CLK_POLARITY_MASK 0x80
|
||||
#define MSPI_CLK_POLARITY_BIT_OFFSET 0x07
|
||||
#define MSPI_CLK_PHASE_MAX 0x1
|
||||
#define MSPI_CLK_POLARITY_MAX 0x1
|
||||
#define MSPI_CLK_CLOCK_MAX 0x7
|
||||
#define MSPI_CTRL_CPOL_LOW 0x00
|
||||
#define MSPI_CTRL_CPOL_HIGH 0x80
|
||||
#define MSPI_CTRL_CPHA_LOW 0x00
|
||||
#define MSPI_CTRL_CPHA_HIGH 0x40
|
||||
#define MSPI_CTRL_3WIRE 0x10
|
||||
#define MSPI_CTRL_INTEN 0x04
|
||||
#define MSPI_CTRL_RESET 0x02
|
||||
#define MSPI_CTRL_ENABLE_SPI 0x01
|
||||
// DC config
|
||||
#define MSPI_DC_MASK 0xFF
|
||||
#define MSPI_DC_BIT_OFFSET 0x08
|
||||
#define MSPI_DC_TR_START_OFFSET 0x4A
|
||||
#define MSPI_DC_TRSTART_MAX 0xFF
|
||||
#define MSPI_DC_TR_END_OFFSET 0x4A
|
||||
#define MSPI_DC_TREND_MAX 0xFF
|
||||
#define MSPI_DC_TB_OFFSET 0x4B
|
||||
#define MSPI_DC_TB_MAX 0xFF
|
||||
#define MSPI_DC_TRW_OFFSET 0x4B
|
||||
#define MSPI_DC_TRW_MAX 0xFF
|
||||
// Frame Config
|
||||
#define MSPI_FRAME_WBIT_OFFSET 0x4C
|
||||
#define MSPI_FRAME_RBIT_OFFSET 0x4E
|
||||
#define MSPI_FRAME_BIT_MAX 0x07
|
||||
#define MSPI_FRAME_BIT_MASK 0x07
|
||||
#define MSPI_FRAME_BIT_FIELD 0x03
|
||||
#define MSPI_LSB_FIRST_OFFSET 0x50
|
||||
#define MSPI_TRIGGER_OFFSET 0x5A
|
||||
#define MSPI_DONE_OFFSET 0x5B
|
||||
#define MSPI_DONE_CLEAR_OFFSET 0x5C
|
||||
#define MSPI_CHIP_SELECT_OFFSET 0x5F
|
||||
#define MSPI_CS1_DISABLE 0x01
|
||||
#define MSPI_CS1_ENABLE 0x00
|
||||
#define MSPI_CS2_DISABLE 0x02
|
||||
#define MSPI_CS2_ENABLE 0x00
|
||||
#define MSPI_CS3_DISABLE 0x04
|
||||
#define MSPI_CS3_ENABLE 0x00
|
||||
#define MSPI_CS4_DISABLE 0x08
|
||||
#define MSPI_CS4_ENABLE 0x00
|
||||
#define MSPI_CS5_DISABLE 0x10
|
||||
#define MSPI_CS5_ENABLE 0x00
|
||||
#define MSPI_CS6_DISABLE 0x20
|
||||
#define MSPI_CS6_ENABLE 0x00
|
||||
#define MSPI_CS7_DISABLE 0x40
|
||||
#define MSPI_CS7_ENABLE 0x00
|
||||
#define MSPI_CS8_DISABLE 0x80
|
||||
#define MSPI_CS8_ENABLE 0x00
|
||||
|
||||
#define MSPI_FULL_DEPLUX_RD_CNT (0x77)
|
||||
#define MSPI_FULL_DEPLUX_RD00 (0x78)
|
||||
#define MSPI_FULL_DEPLUX_RD01 (0x78)
|
||||
#define MSPI_FULL_DEPLUX_RD02 (0x79)
|
||||
#define MSPI_FULL_DEPLUX_RD03 (0x79)
|
||||
#define MSPI_FULL_DEPLUX_RD04 (0x7a)
|
||||
#define MSPI_FULL_DEPLUX_RD05 (0x7a)
|
||||
#define MSPI_FULL_DEPLUX_RD06 (0x7b)
|
||||
#define MSPI_FULL_DEPLUX_RD07 (0x7b)
|
||||
|
||||
#define MSPI_FULL_DEPLUX_RD08 (0x7c)
|
||||
#define MSPI_FULL_DEPLUX_RD09 (0x7c)
|
||||
#define MSPI_FULL_DEPLUX_RD10 (0x7d)
|
||||
#define MSPI_FULL_DEPLUX_RD11 (0x7d)
|
||||
#define MSPI_FULL_DEPLUX_RD12 (0x7e)
|
||||
#define MSPI_FULL_DEPLUX_RD13 (0x7e)
|
||||
#define MSPI_FULL_DEPLUX_RD14 (0x7f)
|
||||
#define MSPI_FULL_DEPLUX_RD15 (0x7f)
|
||||
|
||||
//chip select bit map
|
||||
#define MSPI_CHIP_SELECT_MAX 0x07
|
||||
|
||||
// control bit
|
||||
#define MSPI_DONE_FLAG 0x01
|
||||
#define MSPI_TRIGGER 0x01
|
||||
#define MSPI_CLEAR_DONE 0x01
|
||||
#define MSPI_INT_ENABLE 0x04
|
||||
#define MSPI_RESET 0x02
|
||||
#define MSPI_ENABLE 0x01
|
||||
|
||||
// clk_mspi0
|
||||
#define MSPI0_CLK_CFG 0x33 //bit 2 ~bit 3
|
||||
#define MSPI0_CLK_108M 0x00
|
||||
#define MSPI0_CLK_54M 0x04
|
||||
#define MSPI0_CLK_12M 0x08
|
||||
#define MSPI0_CLK_MASK 0x0F
|
||||
|
||||
// clk_mspi1
|
||||
#define MSPI1_CLK_CFG 0x33 //bit 10 ~bit 11
|
||||
#define MSPI1_CLK_108M 0x0000
|
||||
#define MSPI1_CLK_54M 0x0400
|
||||
#define MSPI1_CLK_12M 0x0800
|
||||
#define MSPI1_CLK_MASK 0x0F00
|
||||
|
||||
// clk_mspi
|
||||
#define MSPI_CLK_CFG 0x33
|
||||
#define MSPI_SELECT_0 0x0000
|
||||
#define MSPI_SELECT_1 0x4000
|
||||
#define MSPI_CLK_MASK 0xF000
|
||||
|
||||
// Clock settings
|
||||
#define MSPI_CPU_CLOCK_1_2 0x0000
|
||||
#define MSPI_CPU_CLOCK_1_4 0x0100
|
||||
#define MSPI_CPU_CLOCK_1_8 0x0200
|
||||
#define MSPI_CPU_CLOCK_1_16 0x0300
|
||||
#define MSPI_CPU_CLOCK_1_32 0x0400
|
||||
#define MSPI_CPU_CLOCK_1_64 0x0500
|
||||
#define MSPI_CPU_CLOCK_1_128 0x0600
|
||||
#define MSPI_CPU_CLOCK_1_256 0x0700
|
||||
|
||||
//CHITOP 101E mspi mode select
|
||||
#define MSPI0_MODE 0x0C //bit0~bit1
|
||||
#define MSPI0_MODE_MASK 0x07
|
||||
#define MSPI1_MODE 0x0C //bit4~bit5
|
||||
#define MSPI1_MODE_MASK 0x70
|
||||
#define EJTAG_MODE 0xF
|
||||
#define EJTAG_MODE_1 0x01
|
||||
#define EJTAG_MODE_2 0x02
|
||||
#define EJTAG_MODE_3 0x03
|
||||
#define EJTAG_MODE_MASK 0x03
|
||||
|
||||
//MOVDMA 100B
|
||||
#define MOV_DMA_SRC_ADDR_L 0x03
|
||||
#define MOV_DMA_SRC_ADDR_H 0x04
|
||||
#define MOV_DMA_DST_ADDR_L 0x05
|
||||
#define MOV_DMA_DST_ADDR_H 0x06
|
||||
#define MOV_DMA_BYTE_CNT_L 0x07
|
||||
#define MOV_DMA_BYTE_CNT_H 0x08
|
||||
#define DMA_MOVE0_IRQ_CLR 0x28
|
||||
#define MOV_DMA_IRQ_FINAL_STATUS 0x2A
|
||||
#define DMA_MOVE0_ENABLE 0x00
|
||||
#define DMA_RW 0x50 //0 for dma write to device, 1 for dma read from device
|
||||
#define DMA_READ 0x01
|
||||
#define DMA_WRITE 0x00
|
||||
#define DMA_DEVICE_MODE 0x51
|
||||
#define DMA_DEVICE_SEL 0x52
|
||||
|
||||
//spi dma
|
||||
#define MSPI_DMA_DATA_LENGTH_L 0x30
|
||||
#define MSPI_DMA_DATA_LENGTH_H 0x31
|
||||
#define MSPI_DMA_ENABLE 0x32
|
||||
#define MSPI_DMA_RW_MODE 0x33
|
||||
#define MSPI_DMA_WRITE 0x00
|
||||
#define MSPI_DMA_READ 0x01
|
||||
|
||||
#define MSTAR_SPI_TIMEOUT_MS 30000
|
||||
#define MSTAR_SPI_MODE_BITS (SPI_CPOL | SPI_CPHA /*| SPI_CS_HIGH | SPI_NO_CS | SPI_LSB_FIRST*/)
|
||||
|
||||
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
// Macros
|
||||
//-------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
#define MHal_CHIPTOP_REG(addr) (*(volatile U8*)((gChipBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_PM_SLEEP_REG(addr) (*(volatile U8*)((gPmSleepBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_SAR_GPIO_REG(addr) (*(volatile U8*)((gSarBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define MHal_RIU_REG(addr) (*(volatile U8*)((gRIUBaseAddr) + (((addr) & ~1)<<1) + (addr & 1)))
|
||||
#define READ_BYTE(_reg) (*(volatile u8*)(_reg))
|
||||
#define READ_WORD(_reg) (*(volatile u16*)(_reg))
|
||||
#define READ_LONG(_reg) (*(volatile u32*)(_reg))
|
||||
#define WRITE_BYTE(_reg, _val) {(*((volatile u8*)(_reg))) = (u8)(_val); }
|
||||
#define WRITE_WORD(_reg, _val) {(*((volatile u16*)(_reg))) = (u16)(_val); }
|
||||
#define WRITE_LONG(_reg, _val) {(*((volatile u32*)(_reg))) = (u32)(_val); }
|
||||
#define WRITE_WORD_MASK(_reg, _val, _mask) {(*((volatile u16*)(_reg))) = ((*((volatile u16*)(_reg))) & ~(_mask)) | ((u16)(_val) & (_mask)); }
|
||||
#define READ_CPLD_DATA_IN() ((MHal_RIU_REG(PAD_Z80IO_IN_DATA_7_ADDR) & 0x1) << 7 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_6_ADDR) & 0x1) << 6 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_5_ADDR) & 0x1) << 5 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_4_ADDR) & 0x1) << 4 |\
|
||||
(MHal_RIU_REG(PAD_Z80IO_IN_DATA_3_ADDR) & 0x1) << 3 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_2_ADDR) & 0x1) << 2 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_1_ADDR) & 0x1) << 1 | (MHal_RIU_REG(PAD_Z80IO_IN_DATA_0_ADDR) & 0x1))
|
||||
#define SET_CPLD_READ_DATA() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
||||
#define SET_CPLD_READ_STATUS() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
||||
#define SET_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) |= 0x4;}
|
||||
#define CLEAR_CPLD_HIGH_BYTE() {MHal_RIU_REG(PAD_Z80IO_HIGH_BYTE_ADDR) &= ~0x4;}
|
||||
#define CPLD_READY() (MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1)
|
||||
#define CPLD_RESET() (MHal_RIU_REG(PAD_Z80IO_RESET_ADDR) & 0x1)
|
||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
// write 2 byte
|
||||
//#define MSPI_WRITE(_reg_, _val_) {pr_info("PDS: MSPI_WRITE(0x%x, 0x%x, 0x%x)\n", _reg_, _val_, gMspBaseAddr + ((_reg_)<<2)); WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define MSPI_WRITE(_reg_, _val_) WRITE_WORD(gMspBaseAddr + ((_reg_)<<2), (_val_));
|
||||
//write 2 byte mask
|
||||
//#define MSPI_WRITE_MASK(_reg_, _val_, mask) {pr_info("PDS: WRITE_LONG(0x%x, 0x%x, mask=0x%x)\n", _reg_, _val_, mask); WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask)); }
|
||||
#define MSPI_WRITE_MASK(_reg_, _val_, mask) WRITE_WORD_MASK(gMspBaseAddr + ((_reg_)<<2), (_val_), (mask));
|
||||
|
||||
#define CLK_READ(_reg_) READ_WORD(gClkBaseAddr + ((_reg_)<<2))
|
||||
//#define CLK_WRITE(_reg_, _val_) {pr_info("PDS: CLK_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define CLK_WRITE(_reg_, _val_) WRITE_WORD(gClkBaseAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define CHIPTOP_READ(_reg_) READ_WORD(gChipBaseAddr + ((_reg_)<<2))
|
||||
//#define CHIPTOP_WRITE(_reg_, _val_) {pr_info("PDS: CHIPTOP_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define CHIPTOP_WRITE(_reg_, _val_) WRITE_WORD(gChipBaseAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define MOVDMA_READ(_reg_) READ_WORD(gMOVDMAAddr + ((_reg_)<<2))
|
||||
//#define MOVDMA_WRITE(_reg_, _val_) {pr_info("PDS: MOVDMA_WRITE(0x%x, 0x%x)\n", _reg_, _val_); WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_)); }
|
||||
#define MOVDMA_WRITE(_reg_, _val_) WRITE_WORD(gMOVDMAAddr + ((_reg_)<<2), (_val_));
|
||||
|
||||
#define _HAL_MSPI_ClearDone() MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET,MSPI_CLEAR_DONE)
|
||||
#define MAX_CHECK_CNT 2000
|
||||
|
||||
#define MSPI_READ_INDEX 0x0
|
||||
#define MSPI_WRITE_INDEX 0x1
|
||||
|
||||
#define SPI_MIU0_BUS_BASE 0x20000000
|
||||
#define SPI_MIU1_BUS_BASE 0xFFFFFFFF
|
||||
|
||||
|
||||
// Function definitions.
|
||||
//
|
||||
int z80io_init(void);
|
||||
uint8_t z80io_SPI_Send8(uint8_t txData, uint8_t *rxData);
|
||||
uint8_t z80io_SPI_Send16(uint16_t txData, uint16_t *rxData);
|
||||
uint8_t z80io_SPI_Send32(uint32_t txData, uint32_t *rxData);
|
||||
#ifdef NOTNEEDED
|
||||
uint8_t z80io_PRL_Send8(uint8_t txData);
|
||||
uint8_t z680io_PRL_Send16(uint16_t txData);
|
||||
#endif
|
||||
uint8_t z80io_PRL_Read8(uint8_t dataFlag);
|
||||
uint16_t z80io_PRL_Read16(void);
|
||||
uint8_t z80io_SPI_Test(void);
|
||||
uint8_t z80io_PRL_Test(void);
|
||||
uint8_t z80io_Z80_TestMemory(void);
|
||||
|
||||
extern void MHal_GPIO_Init(void);
|
||||
extern void MHal_GPIO_Pad_Set(uint8_t u8IndexGPIO);
|
||||
extern int MHal_GPIO_PadGroupMode_Set(uint32_t u32PadMode);
|
||||
extern int MHal_GPIO_PadVal_Set(uint8_t u8IndexGPIO, uint32_t u32PadMode);
|
||||
extern void MHal_GPIO_Pad_Oen(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pad_Odn(uint8_t u8IndexGPIO);
|
||||
extern uint8_t MHal_GPIO_Pad_Level(uint8_t u8IndexGPIO);
|
||||
extern uint8_t MHal_GPIO_Pad_InOut(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pull_High(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Pull_Low(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_High(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_Low(uint8_t u8IndexGPIO);
|
||||
extern void MHal_Enable_GPIO_INT(uint8_t u8IndexGPIO);
|
||||
extern int MHal_GPIO_To_Irq(uint8_t u8IndexGPIO);
|
||||
extern void MHal_GPIO_Set_POLARITY(uint8_t u8IndexGPIO, uint8_t reverse);
|
||||
extern void MHal_GPIO_Set_Driving(uint8_t u8IndexGPIO, uint8_t setHigh);
|
||||
extern void MHal_GPIO_PAD_32K_OUT(uint8_t u8Enable);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // Z80IO_H
|
||||
@@ -1,541 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80io_test.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 IO Interface Test Methods
|
||||
// This file contains the methods used to test the SOM to CPLD interface and evaluate
|
||||
// it's performance. Production builds wont include these methods.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/semaphore.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
//--------------------------------------------------------
|
||||
// Test Methods.
|
||||
//--------------------------------------------------------
|
||||
uint8_t z80io_Z80_TestMemory(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
uint32_t addr;
|
||||
uint32_t fullCmd;
|
||||
uint8_t cmd;
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 100;
|
||||
uint32_t errorCount;
|
||||
uint32_t idx;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
uint8_t result;
|
||||
spinlock_t spinLock;
|
||||
unsigned long flags;
|
||||
|
||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||
|
||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E80000 | (0x82 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E20000 | (0x58 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E00000 | (0xF7 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00E90000 | (0x0F << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00EB0000 | (0xCF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
SPI_SEND32(0x00EB0000 | (0xFF << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
pr_info("Z80 Host Test - IO.\n");
|
||||
for(idx=0; idx < 1000000; idx++)
|
||||
{
|
||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
SPI_SEND32(0xD0000000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
SPI_SEND32(0xD0100000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
SPI_SEND32(0xD0200000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
SPI_SEND32(0xD0300000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
SPI_SEND32(0xD0400000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
SPI_SEND32(0xD0500000 | (0x41 << 8) | CPLD_CMD_WRITE_ADDR);
|
||||
}
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing IO Write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
for(addr=0x0000; addr < 0x10000; addr++)
|
||||
{
|
||||
fullCmd = 0x00000000| ((uint8_t)addr) << 8 | CPLD_CMD_WRITEIO_ADDR;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing IO Read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible IO ports and write to it.
|
||||
for(addr=0x0000; addr < 0x10000; addr++)
|
||||
{
|
||||
fullCmd = 0x00000000 | ((uint8_t)addr) << 8 | CPLD_CMD_READIO_ADDR;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
spin_lock_init(&spinLock);
|
||||
pr_info("Z80 Host Test - Testing RAM Write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write performance (opt).\n");
|
||||
do_gettimeofday(&start);
|
||||
spin_lock_irqsave(&spinLock, flags);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
spin_unlock_irqrestore(&spinLock, flags);
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write/Fetch performance (opt).\n");
|
||||
errorCount = 0;
|
||||
SET_CPLD_READ_DATA();
|
||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x8000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x8000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x10;
|
||||
SPI_SEND8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
if(result != (uint8_t)addr)
|
||||
{
|
||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Write/Read performance (opt).\n");
|
||||
errorCount = 0;
|
||||
SET_CPLD_READ_DATA();
|
||||
//MHal_RIU_REG(gpio_table[PAD_Z80IO_HIGH_BYTE ].r_out) |= gpio_table[PAD_Z80IO_HIGH_BYTE ].m_out;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and write to it.
|
||||
for(addr=0x8000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x8000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND16(((uint8_t)addr) << 8 | cmd);
|
||||
}
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x20;
|
||||
SPI_SEND8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
if(result != (uint8_t)addr)
|
||||
{
|
||||
if(errorCount < 50) pr_info("Read byte:0x%x, Written:0x%x\n", result, (uint8_t)addr);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, errorCount=%d, %ldBytes/sec\n", totalTime/1000, errorCount, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Fetch performance.\n");
|
||||
SET_CPLD_READ_DATA();
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and read from it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x10;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x11;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Z80 Host Test - Testing RAM Read performance (opt).\n");
|
||||
SET_CPLD_READ_DATA();
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible RAM and read from it.
|
||||
for(addr=0x1000; addr < 0xD000; addr++)
|
||||
{
|
||||
if(addr == 0x1000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)addr) << 8 | 0x20;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x21;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations*0xC000)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// Go through all the accessible attribute VRAM and initialise it.
|
||||
pr_info("Z80 Host Test - Testing VRAM Write performance.\n");
|
||||
SPI_SEND32(0x00E80000 | (0xD3 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
iterations = 256*10;
|
||||
do_gettimeofday(&start);
|
||||
for(addr=0xD800; addr < 0xE000; addr++)
|
||||
{
|
||||
//while(CPLD_READY() == 0);
|
||||
if(addr == 0xD800)
|
||||
{
|
||||
fullCmd = (addr << 16) |(0x71 << 8) | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
}
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Go through all the accessible VRAM and write to it.
|
||||
for(addr=0xD000; addr < 0xD800; addr++)
|
||||
{
|
||||
//while(CPLD_READY() == 0);
|
||||
if(addr == 0xD000)
|
||||
{
|
||||
fullCmd = (addr << 16) | ((uint8_t)idx << 8) | 0x18;
|
||||
SPI_SEND32(fullCmd);
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)((1*iterations*0x800)+0x800)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
return(0);
|
||||
}
|
||||
|
||||
|
||||
// A simple test to verify the SOM to CPLD SPI connectivity and give an estimate of its performance.
|
||||
// The performance is based on the SPI setup and transmit time along with the close and received data processing.
|
||||
// In real use, the driver will just send a command and generally ignore received data so increased throughput can be achieved.
|
||||
//
|
||||
uint8_t z80io_SPI_Test(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 10000000;
|
||||
uint32_t idx;
|
||||
uint8_t rxData8;
|
||||
uint16_t rxData16;
|
||||
uint16_t rxData16Last;
|
||||
uint32_t rxData32;
|
||||
uint32_t rxData32Last;
|
||||
uint32_t errorCount;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
|
||||
// Place the CPLD into echo test mode.
|
||||
z80io_SPI_Send8(0xfe, &rxData8);
|
||||
|
||||
// 1st. test, 8bit.
|
||||
pr_info("SPI Test - Testing 8 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
z80io_SPI_Send8((uint8_t)idx, &rxData8);
|
||||
if(idx > 1 && (uint8_t)(idx-1) != rxData8)
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint8_t)(idx-1), rxData8 );
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(1*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 2nd. test, 16bit.
|
||||
pr_info("SPI Test - Testing 16 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
||||
z80io_SPI_Send16((uint16_t)idx, &rxData16);
|
||||
if(idx > 0 && (uint16_t)(idx-1) != (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)))
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint16_t)(idx-1), (uint16_t)(((rxData16&0x00ff) << 8) | ((rxData16Last & 0xff00) >> 8)));
|
||||
errorCount++;
|
||||
}
|
||||
rxData16Last = rxData16;
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 3rd. test, 32bit.
|
||||
pr_info("SPI Test - Testing 32 bit performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
z80io_SPI_Send32((uint32_t)idx, &rxData32);
|
||||
if(idx > 0 && (uint32_t)(idx-1) != (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)))
|
||||
{
|
||||
if(errorCount < 20)
|
||||
pr_info("0x%x: Last(0x%x) /= New(0x%x)\n",idx, (uint32_t)(idx-1), (uint32_t)(((rxData32&0x00ff) << 8) | ((rxData32Last & 0xff000000) >> 8) | ((rxData32Last & 0xff0000) >> 8) | ((rxData32Last & 0xff00) >> 8)));
|
||||
errorCount++;
|
||||
}
|
||||
rxData32Last = rxData32;
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(4*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
||||
return(0);
|
||||
}
|
||||
|
||||
// Method to test the parallel bus, verifying integrity and assessing performance.
|
||||
uint8_t z80io_PRL_Test(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
struct timeval start, stop;
|
||||
uint32_t iterations = 10000000;
|
||||
uint32_t idx;
|
||||
uint8_t rxData8;
|
||||
uint16_t rxData16;
|
||||
long totalTime;
|
||||
long bytesMSec;
|
||||
#ifdef NOTNEEDED
|
||||
uint32_t errorCount;
|
||||
#endif
|
||||
|
||||
// Place the CPLD into echo test mode.
|
||||
|
||||
// 1st. test, 8bit RW.
|
||||
#ifdef NOTNEEDED
|
||||
pr_info("Parallel Test - Testing 8 bit r/w performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write byte and readback to compare.
|
||||
z80io_PRL_Send8((uint8_t)idx);
|
||||
rxData8 = z80io_PRL_Read8();
|
||||
if((uint8_t)idx != rxData8)
|
||||
{
|
||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint8_t)(idx), rxData8);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 2nd. test, 8bit Write.
|
||||
pr_info("Parallel Test - Testing 8 bit write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write byte.
|
||||
z80io_PRL_Send8((uint8_t)idx);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
#endif
|
||||
|
||||
// 3rd. test, 8bit Read.
|
||||
pr_info("Parallel Test - Testing 8 bit read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Read byte.
|
||||
rxData8 = z80io_PRL_Read8(0);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
#ifdef NOTNEEDED
|
||||
// 4th test, 16bit.
|
||||
pr_info("Parallel Test - Testing 16 bit r/w performance.\n");
|
||||
errorCount=0;
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Byte re-ordering required as the CPLD echo's back the last 8bits received, it doesnt know if a transmission is 8/16/32bits.
|
||||
z80io_PRL_Send16((uint16_t)idx);
|
||||
rxData16 = z80io_PRL_Read16();
|
||||
if((uint16_t)idx != rxData16)
|
||||
{
|
||||
pr_info("0x%x: Written(0x%x) /= Read(0x%x)\n", idx, (uint16_t)(idx), rxData16);
|
||||
errorCount++;
|
||||
}
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode errorCount: %d, time=%ldms, %ldBytes/sec\n", errorCount, totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
// 5th test, 16bit Write.
|
||||
pr_info("Parallel Test - Testing 16 bit write performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Write word.
|
||||
z80io_PRL_Send16((uint16_t)idx);
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
#endif
|
||||
|
||||
// 6th test, 16bit Read.
|
||||
pr_info("Parallel Test - Testing 16 bit read performance.\n");
|
||||
do_gettimeofday(&start);
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
{
|
||||
// Read word.
|
||||
rxData16 = z80io_PRL_Read16();
|
||||
}
|
||||
do_gettimeofday(&stop);
|
||||
totalTime = (stop.tv_sec - start.tv_sec) * 1000000 + stop.tv_usec - start.tv_usec;
|
||||
bytesMSec = (long)(2*iterations)/((long)totalTime/1000);
|
||||
pr_info("Loop mode time=%ldms, %ldBytes/sec\n", totalTime/1000, (bytesMSec*1000));
|
||||
|
||||
pr_info("Press host RESET button Once to reset the CPLD.\n");
|
||||
return(0);
|
||||
}
|
||||
@@ -1,57 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80menu.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 User Menu
|
||||
// This file contains the methods used to present a menu of options to a user to aid
|
||||
// in configuration and load/save of applications and data.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
#include "z80menu.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
void z80menu(void)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
}
|
||||
44
software/FusionX/src/z80drv/MZ700/z80menu.h
vendored
44
software/FusionX/src/z80drv/MZ700/z80menu.h
vendored
@@ -1,44 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80menu.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 User Interface Menu
|
||||
// This file contains the declarations required to provide a menu system allowing a
|
||||
// user to configure and load/save applications/data.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80MENU_H
|
||||
#define Z80MENU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Function definitions.
|
||||
//
|
||||
void z80menu(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // Z80MENU_H
|
||||
403
software/FusionX/src/z80drv/MZ80A/optparse.h
vendored
403
software/FusionX/src/z80drv/MZ80A/optparse.h
vendored
@@ -1,403 +0,0 @@
|
||||
/* Optparse --- portable, reentrant, embeddable, getopt-like option parser
|
||||
*
|
||||
* This is free and unencumbered software released into the public domain.
|
||||
*
|
||||
* To get the implementation, define OPTPARSE_IMPLEMENTATION.
|
||||
* Optionally define OPTPARSE_API to control the API's visibility
|
||||
* and/or linkage (static, __attribute__, __declspec).
|
||||
*
|
||||
* The POSIX getopt() option parser has three fatal flaws. These flaws
|
||||
* are solved by Optparse.
|
||||
*
|
||||
* 1) Parser state is stored entirely in global variables, some of
|
||||
* which are static and inaccessible. This means only one thread can
|
||||
* use getopt(). It also means it's not possible to recursively parse
|
||||
* nested sub-arguments while in the middle of argument parsing.
|
||||
* Optparse fixes this by storing all state on a local struct.
|
||||
*
|
||||
* 2) The POSIX standard provides no way to properly reset the parser.
|
||||
* This means for portable code that getopt() is only good for one
|
||||
* run, over one argv with one option string. It also means subcommand
|
||||
* options cannot be processed with getopt(). Most implementations
|
||||
* provide a method to reset the parser, but it's not portable.
|
||||
* Optparse provides an optparse_arg() function for stepping over
|
||||
* subcommands and continuing parsing of options with another option
|
||||
* string. The Optparse struct itself can be passed around to
|
||||
* subcommand handlers for additional subcommand option parsing. A
|
||||
* full reset can be achieved by with an additional optparse_init().
|
||||
*
|
||||
* 3) Error messages are printed to stderr. This can be disabled with
|
||||
* opterr, but the messages themselves are still inaccessible.
|
||||
* Optparse solves this by writing an error message in its errmsg
|
||||
* field. The downside to Optparse is that this error message will
|
||||
* always be in English rather than the current locale.
|
||||
*
|
||||
* Optparse should be familiar with anyone accustomed to getopt(), and
|
||||
* it could be a nearly drop-in replacement. The option string is the
|
||||
* same and the fields have the same names as the getopt() global
|
||||
* variables (optarg, optind, optopt).
|
||||
*
|
||||
* Optparse also supports GNU-style long options with optparse_long().
|
||||
* The interface is slightly different and simpler than getopt_long().
|
||||
*
|
||||
* By default, argv is permuted as it is parsed, moving non-option
|
||||
* arguments to the end. This can be disabled by setting the `permute`
|
||||
* field to 0 after initialization.
|
||||
*/
|
||||
#ifndef OPTPARSE_H
|
||||
#define OPTPARSE_H
|
||||
|
||||
#ifndef OPTPARSE_API
|
||||
# define OPTPARSE_API
|
||||
#endif
|
||||
|
||||
struct optparse {
|
||||
char **argv;
|
||||
int permute;
|
||||
int optind;
|
||||
int optopt;
|
||||
char *optarg;
|
||||
char errmsg[64];
|
||||
int subopt;
|
||||
};
|
||||
|
||||
enum optparse_argtype {
|
||||
OPTPARSE_NONE,
|
||||
OPTPARSE_REQUIRED,
|
||||
OPTPARSE_OPTIONAL
|
||||
};
|
||||
|
||||
struct optparse_long {
|
||||
const char *longname;
|
||||
int shortname;
|
||||
enum optparse_argtype argtype;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes the parser state.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
void optparse_init(struct optparse *options, char **argv);
|
||||
|
||||
/**
|
||||
* Read the next option in the argv array.
|
||||
* @param optstring a getopt()-formatted option string.
|
||||
* @return the next option character, -1 for done, or '?' for error
|
||||
*
|
||||
* Just like getopt(), a character followed by no colons means no
|
||||
* argument. One colon means the option has a required argument. Two
|
||||
* colons means the option takes an optional argument.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
int optparse(struct optparse *options, const char *optstring);
|
||||
|
||||
/**
|
||||
* Handles GNU-style long options in addition to getopt() options.
|
||||
* This works a lot like GNU's getopt_long(). The last option in
|
||||
* longopts must be all zeros, marking the end of the array. The
|
||||
* longindex argument may be NULL.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
int optparse_long(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex);
|
||||
|
||||
/**
|
||||
* Used for stepping over non-option arguments.
|
||||
* @return the next non-option argument, or NULL for no more arguments
|
||||
*
|
||||
* Argument parsing can continue with optparse() after using this
|
||||
* function. That would be used to parse the options for the
|
||||
* subcommand returned by optparse_arg(). This function allows you to
|
||||
* ignore the value of optind.
|
||||
*/
|
||||
OPTPARSE_API
|
||||
char *optparse_arg(struct optparse *options);
|
||||
|
||||
/* Implementation */
|
||||
#ifdef OPTPARSE_IMPLEMENTATION
|
||||
|
||||
#define OPTPARSE_MSG_INVALID "invalid option"
|
||||
#define OPTPARSE_MSG_MISSING "option requires an argument"
|
||||
#define OPTPARSE_MSG_TOOMANY "option takes no arguments"
|
||||
|
||||
static int
|
||||
optparse_error(struct optparse *options, const char *msg, const char *data)
|
||||
{
|
||||
unsigned p = 0;
|
||||
const char *sep = " -- '";
|
||||
while (*msg)
|
||||
options->errmsg[p++] = *msg++;
|
||||
while (*sep)
|
||||
options->errmsg[p++] = *sep++;
|
||||
while (p < sizeof(options->errmsg) - 2 && *data)
|
||||
options->errmsg[p++] = *data++;
|
||||
options->errmsg[p++] = '\'';
|
||||
options->errmsg[p++] = '\0';
|
||||
return '?';
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
void
|
||||
optparse_init(struct optparse *options, char **argv)
|
||||
{
|
||||
options->argv = argv;
|
||||
options->permute = 1;
|
||||
options->optind = 1;
|
||||
options->subopt = 0;
|
||||
options->optarg = 0;
|
||||
options->errmsg[0] = '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_dashdash(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] == '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_shortopt(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] != '-' && arg[1] != '\0';
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_is_longopt(const char *arg)
|
||||
{
|
||||
return arg != 0 && arg[0] == '-' && arg[1] == '-' && arg[2] != '\0';
|
||||
}
|
||||
|
||||
static void
|
||||
optparse_permute(struct optparse *options, int index)
|
||||
{
|
||||
char *nonoption = options->argv[index];
|
||||
int i;
|
||||
for (i = index; i < options->optind - 1; i++)
|
||||
options->argv[i] = options->argv[i + 1];
|
||||
options->argv[options->optind - 1] = nonoption;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_argtype(const char *optstring, char c)
|
||||
{
|
||||
int count = OPTPARSE_NONE;
|
||||
if (c == ':')
|
||||
return -1;
|
||||
for (; *optstring && c != *optstring; optstring++);
|
||||
if (!*optstring)
|
||||
return -1;
|
||||
if (optstring[1] == ':')
|
||||
count += optstring[2] == ':' ? 2 : 1;
|
||||
return count;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
int
|
||||
optparse(struct optparse *options, const char *optstring)
|
||||
{
|
||||
int type;
|
||||
char *next;
|
||||
char *option = options->argv[options->optind];
|
||||
options->errmsg[0] = '\0';
|
||||
options->optopt = 0;
|
||||
options->optarg = 0;
|
||||
if (option == 0) {
|
||||
return -1;
|
||||
} else if (optparse_is_dashdash(option)) {
|
||||
options->optind++; /* consume "--" */
|
||||
return -1;
|
||||
} else if (!optparse_is_shortopt(option)) {
|
||||
if (options->permute) {
|
||||
int index = options->optind++;
|
||||
int r = optparse(options, optstring);
|
||||
optparse_permute(options, index);
|
||||
options->optind--;
|
||||
return r;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
option += options->subopt + 1;
|
||||
options->optopt = option[0];
|
||||
type = optparse_argtype(optstring, option[0]);
|
||||
next = options->argv[options->optind + 1];
|
||||
switch (type) {
|
||||
case -1: {
|
||||
char str[2] = {0, 0};
|
||||
str[0] = option[0];
|
||||
options->optind++;
|
||||
return optparse_error(options, OPTPARSE_MSG_INVALID, str);
|
||||
}
|
||||
case OPTPARSE_NONE:
|
||||
if (option[1]) {
|
||||
options->subopt++;
|
||||
} else {
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
}
|
||||
return option[0];
|
||||
case OPTPARSE_REQUIRED:
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
if (option[1]) {
|
||||
options->optarg = option + 1;
|
||||
} else if (next != 0) {
|
||||
options->optarg = next;
|
||||
options->optind++;
|
||||
} else {
|
||||
char str[2] = {0, 0};
|
||||
str[0] = option[0];
|
||||
options->optarg = 0;
|
||||
return optparse_error(options, OPTPARSE_MSG_MISSING, str);
|
||||
}
|
||||
return option[0];
|
||||
case OPTPARSE_OPTIONAL:
|
||||
options->subopt = 0;
|
||||
options->optind++;
|
||||
if (option[1])
|
||||
options->optarg = option + 1;
|
||||
else
|
||||
options->optarg = 0;
|
||||
return option[0];
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
char *
|
||||
optparse_arg(struct optparse *options)
|
||||
{
|
||||
char *option = options->argv[options->optind];
|
||||
options->subopt = 0;
|
||||
if (option != 0)
|
||||
options->optind++;
|
||||
return option;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_longopts_end(const struct optparse_long *longopts, int i)
|
||||
{
|
||||
return !longopts[i].longname && !longopts[i].shortname;
|
||||
}
|
||||
|
||||
static void
|
||||
optparse_from_long(const struct optparse_long *longopts, char *optstring)
|
||||
{
|
||||
char *p = optstring;
|
||||
int i;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
||||
if (longopts[i].shortname && longopts[i].shortname < 127) {
|
||||
int a;
|
||||
*p++ = longopts[i].shortname;
|
||||
for (a = 0; a < (int)longopts[i].argtype; a++)
|
||||
*p++ = ':';
|
||||
}
|
||||
}
|
||||
*p = '\0';
|
||||
}
|
||||
|
||||
/* Unlike strcmp(), handles options containing "=". */
|
||||
static int
|
||||
optparse_longopts_match(const char *longname, const char *option)
|
||||
{
|
||||
const char *a = option, *n = longname;
|
||||
if (longname == 0)
|
||||
return 0;
|
||||
for (; *a && *n && *a != '='; a++, n++)
|
||||
if (*a != *n)
|
||||
return 0;
|
||||
return *n == '\0' && (*a == '\0' || *a == '=');
|
||||
}
|
||||
|
||||
/* Return the part after "=", or NULL. */
|
||||
static char *
|
||||
optparse_longopts_arg(char *option)
|
||||
{
|
||||
for (; *option && *option != '='; option++);
|
||||
if (*option == '=')
|
||||
return option + 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
optparse_long_fallback(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex)
|
||||
{
|
||||
int result;
|
||||
char optstring[96 * 3 + 1]; /* 96 ASCII printable characters */
|
||||
optparse_from_long(longopts, optstring);
|
||||
result = optparse(options, optstring);
|
||||
if (longindex != 0) {
|
||||
*longindex = -1;
|
||||
if (result != -1) {
|
||||
int i;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++)
|
||||
if (longopts[i].shortname == options->optopt)
|
||||
*longindex = i;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
OPTPARSE_API
|
||||
int
|
||||
optparse_long(struct optparse *options,
|
||||
const struct optparse_long *longopts,
|
||||
int *longindex)
|
||||
{
|
||||
int i;
|
||||
char *option = options->argv[options->optind];
|
||||
if (option == 0) {
|
||||
return -1;
|
||||
} else if (optparse_is_dashdash(option)) {
|
||||
options->optind++; /* consume "--" */
|
||||
return -1;
|
||||
} else if (optparse_is_shortopt(option)) {
|
||||
return optparse_long_fallback(options, longopts, longindex);
|
||||
} else if (!optparse_is_longopt(option)) {
|
||||
if (options->permute) {
|
||||
int index = options->optind++;
|
||||
int r = optparse_long(options, longopts, longindex);
|
||||
optparse_permute(options, index);
|
||||
options->optind--;
|
||||
return r;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Parse as long option. */
|
||||
options->errmsg[0] = '\0';
|
||||
options->optopt = 0;
|
||||
options->optarg = 0;
|
||||
option += 2; /* skip "--" */
|
||||
options->optind++;
|
||||
for (i = 0; !optparse_longopts_end(longopts, i); i++) {
|
||||
const char *name = longopts[i].longname;
|
||||
if (optparse_longopts_match(name, option)) {
|
||||
char *arg;
|
||||
if (longindex)
|
||||
*longindex = i;
|
||||
options->optopt = longopts[i].shortname;
|
||||
arg = optparse_longopts_arg(option);
|
||||
if (longopts[i].argtype == OPTPARSE_NONE && arg != 0) {
|
||||
return optparse_error(options, OPTPARSE_MSG_TOOMANY, name);
|
||||
} if (arg != 0) {
|
||||
options->optarg = arg;
|
||||
} else if (longopts[i].argtype == OPTPARSE_REQUIRED) {
|
||||
options->optarg = options->argv[options->optind];
|
||||
if (options->optarg == 0)
|
||||
return optparse_error(options, OPTPARSE_MSG_MISSING, name);
|
||||
else
|
||||
options->optind++;
|
||||
}
|
||||
return options->optopt;
|
||||
}
|
||||
}
|
||||
return optparse_error(options, OPTPARSE_MSG_INVALID, option);
|
||||
}
|
||||
|
||||
#endif /* OPTPARSE_IMPLEMENTATION */
|
||||
#endif /* OPTPARSE_H */
|
||||
@@ -1,57 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80menu.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 User Menu
|
||||
// This file contains the methods used to present a menu of options to a user to aid
|
||||
// in configuration and load/save of applications and data.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
#include "z80menu.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
void z80menu(void)
|
||||
{
|
||||
// Locals.
|
||||
|
||||
}
|
||||
44
software/FusionX/src/z80drv/MZ80A/z80menu.h
vendored
44
software/FusionX/src/z80drv/MZ80A/z80menu.h
vendored
@@ -1,44 +0,0 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80menu.h
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 User Interface Menu
|
||||
// This file contains the declarations required to provide a menu system allowing a
|
||||
// user to configure and load/save applications/data.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2022 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Oct 2022 - Initial write of the z80 kernel driver software.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#ifndef Z80MENU_H
|
||||
#define Z80MENU_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Function definitions.
|
||||
//
|
||||
void z80menu(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif // Z80MENU_H
|
||||
61
software/FusionX/src/z80drv/Makefile
vendored
61
software/FusionX/src/z80drv/Makefile
vendored
@@ -1,40 +1,85 @@
|
||||
#MODEL := MZ2000
|
||||
#MODEL := MZ700
|
||||
MODEL := MZ80A
|
||||
#MODEL := MZ80A
|
||||
#MODEL := PCW8XXX
|
||||
#MODEL := PCW9XXX
|
||||
KERNEL := $(PWD)/../../../linux/kernel
|
||||
FUSIONX := $(PWD)/../..
|
||||
CROSS := arm-linux-gnueabihf-
|
||||
ccflags-y += -O2 -I${src}/Zeta/API -I${src}/Z80/API -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__
|
||||
CTRLINC += -IZeta/API -IZ80/API
|
||||
ccflags-y = -O2 -I${src}/Zeta/API -I${src}/Z80/API -I${KERNEL}/drivers/sstar/include -I${KERNEL}/drivers/sstar/include/infinity2m -I${KERNEL}/drivers/sstar/gpio/infinity2m -D__KERNEL_DRIVER__ -DTARGET_HOST_$(MODEL)=1
|
||||
CTRLINC = -IZeta/API -IZ80/API -DTARGET_HOST_$(MODEL)=1
|
||||
|
||||
obj-m += z80drv.o
|
||||
z80drv-objs += $(MODEL)/z80driver.o Z80.o $(MODEL)/z80io.o $(MODEL)/z80menu.o # emumz.o sharpmz.o osd.o
|
||||
z80drv-objs += src/z80driver.o Z80.o src/z80io.o src/z80menu.o # emumz.o sharpmz.o osd.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/gpio_table.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_gpio.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/mhal_pinmux.o
|
||||
z80drv-objs += ../../../linux/kernel/drivers/sstar/gpio/infinity2m/padmux_tables.o
|
||||
|
||||
|
||||
all:
|
||||
all:
|
||||
@echo "Specify target host, ie. make <host>"
|
||||
@echo "Supported hosts: MZ80A, MZ700, MZ2000, PCW8XXX, PCW9XXX"
|
||||
|
||||
MZ80A: MODEL_MZ80A
|
||||
MZ700: MODEL_MZ700
|
||||
MZ2000: MODEL_MZ2000
|
||||
PCW8XXX: MODEL_PCW8XXX
|
||||
PCW9XXX: MODEL_PCW9XXX
|
||||
|
||||
MODEL_MZ80A:
|
||||
$(MAKE) MODEL=MZ80A BUILD_MZ80A
|
||||
MODEL_MZ700:
|
||||
$(MAKE) MODEL=MZ700 BUILD_MZ700
|
||||
MODEL_MZ2000:
|
||||
$(MAKE) MODEL=MZ2000 BUILD_MZ2000
|
||||
MODEL_PCW8XXX:
|
||||
$(MAKE) MODEL=PCW8XXX BUILD_PCW8XXX
|
||||
MODEL_PCW9XXX:
|
||||
$(MAKE) MODEL=PCW8XXX BUILD_PCW9XXX
|
||||
|
||||
BUILD_MZ80A: sharpbiter k64fcpu kmod z80ctrl
|
||||
BUILD_MZ700: sharpbiter k64fcpu kmod z80ctrl
|
||||
BUILD_MZ2000: sharpbiter k64fcpu kmod z80ctrl
|
||||
BUILD_PCW8XXX: kmod z80ctrl
|
||||
BUILD_PCW9XXX: kmod z80ctrl
|
||||
|
||||
|
||||
sharpbiter:
|
||||
@echo ""
|
||||
@echo "Build Sharp MZ Arbiter for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/sharpbiter.c -o sharpbiter
|
||||
$(CROSS)gcc $(CTRLINC) src/sharpbiter.c -o sharpbiter
|
||||
|
||||
k64fcpu:
|
||||
@echo ""
|
||||
@echo "Build K64F Daemon for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/k64fcpu.c -o k64fcpu
|
||||
$(CROSS)gcc $(CTRLINC) src/k64fcpu.c -o k64fcpu
|
||||
|
||||
kmod:
|
||||
@echo ""
|
||||
@echo "Build driver for host: $(MODEL)"
|
||||
make -C $(KERNEL) ARCH=arm CROSS_COMPILE=$(CROSS) M="$(PWD)" modules
|
||||
|
||||
z80ctrl:
|
||||
@echo ""
|
||||
@echo "Build z80ctrl tool for host: $(MODEL)"
|
||||
$(CROSS)gcc $(CTRLINC) $(MODEL)/z80ctrl.c -o z80ctrl
|
||||
$(CROSS)gcc $(CTRLINC) src/z80ctrl.c -o z80ctrl
|
||||
|
||||
install:
|
||||
@echo "Copy kernel driver..."
|
||||
@cp z80drv.ko $(FUSIONX)/modules/
|
||||
@echo "Copy z80ctrl app..."
|
||||
@cp z80ctrl $(FUSIONX)/bin/
|
||||
@if [ -f sharpbiter ]; then\
|
||||
echo "Copy sharpbiter app...";\
|
||||
cp sharpbiter $(FUSIONX)/bin/;\
|
||||
fi
|
||||
@if [ -f k64fcpu ]; then\
|
||||
echo "Copy k64fcpu app...";\
|
||||
cp k64fcpu $(FUSIONX)/bin/;\
|
||||
fi
|
||||
|
||||
clean:
|
||||
make -C $(KERNEL) M=$(PWD) clean
|
||||
@rm -f sharpbiter k64fcpu z80ctrl
|
||||
|
||||
|
||||
2
software/FusionX/src/z80drv/Z80
vendored
2
software/FusionX/src/z80drv/Z80
vendored
Submodule software/FusionX/src/z80drv/Z80 updated: 75d01a9cca...ada1e2921f
6127
software/FusionX/src/z80drv/src/emumz.c
Normal file
6127
software/FusionX/src/z80drv/src/emumz.c
Normal file
File diff suppressed because it is too large
Load Diff
@@ -183,16 +183,10 @@ int getch(uint8_t wait)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void delay(int number_of_seconds)
|
||||
// Millisecond delay routine.
|
||||
void delay(int ms_delay)
|
||||
{
|
||||
// Converting time into milli_seconds
|
||||
int milli_seconds = 1000 * number_of_seconds;
|
||||
|
||||
// Storing start time
|
||||
clock_t start_time = clock();
|
||||
|
||||
// looping till required time is not achieved
|
||||
while (clock() < start_time + milli_seconds);
|
||||
usleep(1000 * ms_delay);
|
||||
}
|
||||
|
||||
// Function to dump out a given section of memory via the UART.
|
||||
@@ -2799,6 +2793,7 @@ void z80ResetRequest(int signalNo)
|
||||
svcCacheDir(TZSVC_DEFAULT_MZF_DIR, MZF, 1);
|
||||
|
||||
// Start the Z80 after initialisation of the memory.
|
||||
delay(500);
|
||||
startZ80(TZMM_BOOT);
|
||||
return;
|
||||
}
|
||||
@@ -2925,6 +2920,18 @@ int main(int argc, char *argv[])
|
||||
printf("Failed to open the Z80 Driver, exiting...\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
// Setup host type, at the moment this is static but as the FusionX progresses and it can be hosted in multiple hosts without firmware change, then we can pull the
|
||||
// host type from the detected hardware.
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
z80Control.hostType = HW_MZ80A;
|
||||
#elif (TARGET_HOST_MZ700 == 1)
|
||||
z80Control.hostType = HW_MZ700;
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
z80Control.hostType = HW_MZ2000;
|
||||
#else
|
||||
#error "Unknown host, update code to accommodate."
|
||||
#endif
|
||||
|
||||
// Register the service request handler.
|
||||
signal(SIGIO, z80ServiceRequest);
|
||||
@@ -101,9 +101,15 @@ static t_Z80Ctrl *Z80Ctrl = NULL;
|
||||
static uint8_t *Z80RAM = NULL;
|
||||
static uint8_t *Z80ROM = NULL;
|
||||
|
||||
// Millisecond delay routine.
|
||||
void delay(int ms_delay)
|
||||
{
|
||||
usleep(1000 * ms_delay);
|
||||
}
|
||||
|
||||
// Method to reset the Z80 CPU.
|
||||
//
|
||||
void reqResetZ80(uint8_t memoryMode)
|
||||
void reqResetZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
@@ -116,7 +122,7 @@ void reqResetZ80(uint8_t memoryMode)
|
||||
|
||||
// Method to start the Z80 CPU.
|
||||
//
|
||||
void startZ80(uint8_t memoryMode)
|
||||
void startZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
@@ -129,7 +135,7 @@ void startZ80(uint8_t memoryMode)
|
||||
|
||||
// Method to stop the Z80 CPU.
|
||||
//
|
||||
void stopZ80(uint8_t memoryMode)
|
||||
void stopZ80(void)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
@@ -323,24 +329,42 @@ int main(int argc, char *argv[])
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Add in the required driver.
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
#endif
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Reset and start the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
delay(500);
|
||||
reqResetZ80();
|
||||
break;
|
||||
|
||||
case HOTKEY_RFS80:
|
||||
@@ -349,12 +373,21 @@ int main(int argc, char *argv[])
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
@@ -368,10 +401,8 @@ int main(int argc, char *argv[])
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Reset and start the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
delay(500);
|
||||
reqResetZ80();
|
||||
break;
|
||||
|
||||
case HOTKEY_TZFS:
|
||||
@@ -379,12 +410,21 @@ int main(int argc, char *argv[])
|
||||
ioctl(arbCtrl.fdTTY, IOCTL_CMD_SUSPEND_IO, &result);
|
||||
|
||||
// Stop the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_STOP;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
stopZ80();
|
||||
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
@@ -396,12 +436,6 @@ int main(int argc, char *argv[])
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
|
||||
// Reset and start the Z80.
|
||||
ioctlCmd.cmd = IOCTL_CMD_Z80_RESET;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
// ioctlCmd.cmd = IOCTL_CMD_Z80_START;
|
||||
// ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
break;
|
||||
|
||||
case HOTKEY_LINUX:
|
||||
@@ -412,6 +446,16 @@ int main(int argc, char *argv[])
|
||||
// Remove drivers. Remove all because an external event could have changed last configured driver.
|
||||
//
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ2000 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
#endif
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS80;
|
||||
ioctl(arbCtrl.fdZ80, IOCTL_CMD_SEND, &ioctlCmd);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_RFS40;
|
||||
@@ -46,7 +46,13 @@
|
||||
#define REFRESH_BYTE_COUNT 8 // This constant controls the number of bytes read/written to the z80 bus before a refresh cycle is needed.
|
||||
#define RFSH_BYTE_CNT 256 // Number of bytes we can write before needing a full refresh for the DRAM.
|
||||
#define HOST_MON_TEST_VECTOR 0x4 // Address in the host monitor to test to identify host type.
|
||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-80A/" // Linux base directory where all the files are stored. On a real tranZPUter this would be the SD card root dir.
|
||||
#if (TARGET_HOST_MZ80A == 1)
|
||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-80A/" // Linux base directory where all the files are stored. On a real tranZPUter this would be the SD card root dir.
|
||||
#elif (TARGET_HOST_MZ700 == 1)
|
||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-700/"
|
||||
#elif (TARGET_HOST_MZ2000 == 1)
|
||||
#define OS_BASE_DIR "/apps/FusionX/host/MZ-2000/"
|
||||
#endif
|
||||
#define TZFS_AUTOBOOT_FLAG OS_BASE_DIR "/TZFSBOOT.FLG" // Filename used as a flag, if this file exists in the base directory then TZFS is booted automatically.
|
||||
#define TZ_MAX_Z80_MEM 0x100000 // Maximum Z80 memory available on the tranZPUter board.
|
||||
|
||||
@@ -593,6 +593,23 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ80A") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ700") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ2000") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "PCW") == 0)
|
||||
{
|
||||
printf("Add device:%s\n", (char *)param1);
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_PCW;
|
||||
}
|
||||
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
||||
{
|
||||
ioctlCmd.cmd = IOCTL_CMD_ADD_DEVICE;
|
||||
@@ -613,6 +630,22 @@ int ctrlCmd(int fdZ80, enum CTRL_COMMANDS cmd, long param1, long param2, long pa
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_TZPU;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ80A") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ80A;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ700") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ700;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "MZ2000") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_MZ2000;
|
||||
}
|
||||
else if(strcasecmp((char *)param1, "PCW") == 0)
|
||||
{
|
||||
ioctlCmd.vdev.device = VIRTUAL_DEVICE_PCW;
|
||||
}
|
||||
if(ioctlCmd.vdev.device != VIRTUAL_DEVICE_NONE)
|
||||
{
|
||||
ioctlCmd.cmd = IOCTL_CMD_DEL_DEVICE;
|
||||
@@ -749,7 +782,7 @@ void showArgs(char *progName, struct optparse *options)
|
||||
printf(" # Load contents of binary file into memory at address. default = 0x000000.\n");
|
||||
printf(" = LOADMEM --file <binary filename> --addr <24 bit addr> --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM> [--offset <offset> --len <length>]\n");
|
||||
printf(" = SAVE --file <filename> --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = PageTable, 4 = IOPageTable>\n");
|
||||
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = MemoryPageTable, 4 = IOPageTable> [--memorypage <0..31>]\n");
|
||||
printf(" = DUMP --addr <24bit addr> --end <24bit addr> [--size <24bit>] --type <0 - Host RAM, 1 = Virtual RAM, 2 = Virtual ROM, 3 = MemoryPageTable, 4 = IOPageTable> [--memorypage <0..41>]\n");
|
||||
printf(" = CPLDCMD --data <32bit command> # Send adhoc 32bit command to CPLD.\n");
|
||||
#if(DEBUG_ENABLED != 0)
|
||||
printf(" = DEBUG --level <level> # 0 = off, 1..15 debug level, 15 is very verbose.\n");
|
||||
File diff suppressed because it is too large
Load Diff
@@ -35,16 +35,41 @@
|
||||
#ifndef Z80DRIVER_H
|
||||
#define Z80DRIVER_H
|
||||
|
||||
// Build time target. Overrides if compile time definition given.
|
||||
#if defined(TARGET_HOST_MZ700)
|
||||
#define TARGET_HOST_MZ700 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ2000)
|
||||
#define TARGET_HOST_MZ2000 1
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_MZ80A)
|
||||
#define TARGET_HOST_MZ80A 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_PCW 0
|
||||
#elif defined(TARGET_HOST_PCW8XXX) || defined(TARGET_HOST_PCW9XXX)
|
||||
#define TARGET_HOST_PCW 1
|
||||
#define TARGET_HOST_MZ2000 0
|
||||
#define TARGET_HOST_MZ700 0
|
||||
#define TARGET_HOST_MZ80A 0
|
||||
#else
|
||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||
#define TARGET_HOST_MZ80A 0 // MZ80A
|
||||
#define TARGET_HOST_PCW 0 // Amstrad PCW8XXX/9XXX
|
||||
#endif
|
||||
|
||||
// Constants.
|
||||
#define DRIVER_LICENSE "GPL"
|
||||
#define DRIVER_AUTHOR "Philip D Smart"
|
||||
#define DRIVER_DESCRIPTION "Z80 CPU Emulator and Hardware Interface Driver"
|
||||
#define DRIVER_VERSION "v1.3"
|
||||
#define DRIVER_VERSION_DATE "Feb 2023"
|
||||
#define DRIVER_VERSION "v1.4"
|
||||
#define DRIVER_VERSION_DATE "Apr 2023"
|
||||
#define DRIVER_COPYRIGHT "(C) 2018-2023"
|
||||
#define TARGET_HOST_MZ700 0 // Target compilation for an MZ700
|
||||
#define TARGET_HOST_MZ2000 0 // MZ2000
|
||||
#define TARGET_HOST_MZ80A 1 // MZ80A
|
||||
#define Z80_VIRTUAL_ROM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M which is 4x512K ROMS.
|
||||
#define Z80_VIRTUAL_RAM_SIZE (65536 * 32) // Sized to maximum Kernel contiguous allocation size, 2M.
|
||||
#define Z80_MEMORY_PAGE_SIZE 16
|
||||
@@ -69,13 +94,14 @@
|
||||
#define MEMORY_TYPE_VIRTUAL_ROM 0x04000000
|
||||
#define MEMORY_TYPE_VIRTUAL_RAM_RO 0x02000000
|
||||
#define MEMORY_TYPE_VIRTUAL_HW 0x01000000
|
||||
#define MEMORY_TYPE_PHYSICAL_RAM_WT MEMORY_TYPE_PHYSICAL_RAM | MEMORY_TYPE_VIRTUAL_RAM
|
||||
#define IO_TYPE_PHYSICAL_HW 0x80000000
|
||||
#define IO_TYPE_VIRTUAL_HW 0x40000000
|
||||
|
||||
// Hotkeys handled.
|
||||
#define HOTKEY_ORIGINAL 0xE8
|
||||
#define HOTKEY_RFS80 0xE9
|
||||
#define HOTKEY_RFS40 0xEA
|
||||
#define HOTKEY_RFS40 0xE9
|
||||
#define HOTKEY_RFS80 0xEA
|
||||
#define HOTKEY_TZFS 0xEB
|
||||
#define HOTKEY_LINUX 0xEC
|
||||
|
||||
@@ -100,22 +126,42 @@
|
||||
// Approximate governor delays to regulate emulated CPU speed.
|
||||
// MZ-700
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||
#if(DEBUG_ENABLED > 0)
|
||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||
#endif
|
||||
#if(DEBUG_ENABLED == 0)
|
||||
#define INSTRUCTION_DELAY_ROM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_ROM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_ROM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_ROM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_ROM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_ROM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_ROM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_ROM_448MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_3_54MHZ 253
|
||||
#define INSTRUCTION_DELAY_RAM_7MHZ 126
|
||||
#define INSTRUCTION_DELAY_RAM_14MHZ 63
|
||||
#define INSTRUCTION_DELAY_RAM_28MHZ 32
|
||||
#define INSTRUCTION_DELAY_RAM_56MHZ 16
|
||||
#define INSTRUCTION_DELAY_RAM_112MHZ 8
|
||||
#define INSTRUCTION_DELAY_RAM_224MHZ 4
|
||||
#define INSTRUCTION_DELAY_RAM_448MHZ 1
|
||||
#endif
|
||||
#define INSTRUCTION_EQUIV_FREQ_3_54MHZ 3540000
|
||||
#define INSTRUCTION_EQUIV_FREQ_7MHZ 7000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_14MHZ 14000000
|
||||
@@ -124,6 +170,7 @@
|
||||
#define INSTRUCTION_EQUIV_FREQ_112MHZ 112000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_224MHZ 224000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_448MHZ 448000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 10
|
||||
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_3_54MHZ,
|
||||
@@ -141,7 +188,7 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_56MHZ,
|
||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_112MHZ,
|
||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_224MHZ,
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_448MHZ,
|
||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_3_54MHZ,
|
||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_7MHZ,
|
||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_14MHZ,
|
||||
@@ -155,22 +202,43 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
|
||||
// MZ-2000
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 243
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 122
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 61
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 30
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 15
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 218
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 112
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 56
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 28
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 14
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_512MHZ 1
|
||||
|
||||
#if(DEBUG_ENABLED > 0)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 213
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 109
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 54
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 27
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 14
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 1
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 212
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 106
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 53
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 26
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 13
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 7
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_512MHZ 1
|
||||
#endif
|
||||
#if(DEBUG_ENABLED == 0)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 240 // These values are smaller than the ROM as Rom has 1 wait state added per cycle.
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||
#endif
|
||||
#define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_16MHZ 16000000
|
||||
@@ -179,6 +247,7 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_512MHZ 512000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 4
|
||||
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_4MHZ,
|
||||
@@ -258,6 +327,7 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
#define INSTRUCTION_EQUIV_FREQ_64MHZ 64000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 2
|
||||
|
||||
// Table of governor delays to be used to control run frequency,
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
@@ -288,6 +358,82 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
};
|
||||
#endif
|
||||
|
||||
// Amstrad PCW-8256
|
||||
#if(TARGET_HOST_PCW == 1)
|
||||
#if(DEBUG_ENABLED > 0)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 240
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||
#endif
|
||||
#if(DEBUG_ENABLED == 0)
|
||||
#define INSTRUCTION_DELAY_ROM_4MHZ 295
|
||||
#define INSTRUCTION_DELAY_ROM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_ROM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_ROM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_ROM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_ROM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_ROM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_ROM_512MHZ 3
|
||||
#define INSTRUCTION_DELAY_RAM_4MHZ 240
|
||||
#define INSTRUCTION_DELAY_RAM_8MHZ 148
|
||||
#define INSTRUCTION_DELAY_RAM_16MHZ 74
|
||||
#define INSTRUCTION_DELAY_RAM_32MHZ 37
|
||||
#define INSTRUCTION_DELAY_RAM_64MHZ 19
|
||||
#define INSTRUCTION_DELAY_RAM_128MHZ 10
|
||||
#define INSTRUCTION_DELAY_RAM_256MHZ 5
|
||||
#define INSTRUCTION_DELAY_RAM_512MHZ 3
|
||||
#endif
|
||||
#define INSTRUCTION_EQUIV_FREQ_4MHZ 4000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_8MHZ 8000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_16MHZ 16000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_32MHZ 32000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_64MHZ 64000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_128MHZ 128000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_256MHZ 256000000
|
||||
#define INSTRUCTION_EQUIV_FREQ_512MHZ 512000000
|
||||
#define INSTRUCTION_GOVERNOR_IO_SKIP 5
|
||||
|
||||
enum Z80_INSTRUCTION_DELAY {
|
||||
ROM_DELAY_NORMAL = INSTRUCTION_DELAY_ROM_4MHZ,
|
||||
ROM_DELAY_X2 = INSTRUCTION_DELAY_ROM_8MHZ,
|
||||
ROM_DELAY_X4 = INSTRUCTION_DELAY_ROM_16MHZ,
|
||||
ROM_DELAY_X8 = INSTRUCTION_DELAY_ROM_32MHZ,
|
||||
ROM_DELAY_X16 = INSTRUCTION_DELAY_ROM_64MHZ,
|
||||
ROM_DELAY_X32 = INSTRUCTION_DELAY_ROM_128MHZ,
|
||||
ROM_DELAY_X64 = INSTRUCTION_DELAY_ROM_256MHZ,
|
||||
ROM_DELAY_X128 = INSTRUCTION_DELAY_ROM_512MHZ,
|
||||
RAM_DELAY_NORMAL = INSTRUCTION_DELAY_RAM_4MHZ,
|
||||
RAM_DELAY_X2 = INSTRUCTION_DELAY_RAM_8MHZ,
|
||||
RAM_DELAY_X4 = INSTRUCTION_DELAY_RAM_16MHZ,
|
||||
RAM_DELAY_X8 = INSTRUCTION_DELAY_RAM_32MHZ,
|
||||
RAM_DELAY_X16 = INSTRUCTION_DELAY_RAM_64MHZ,
|
||||
RAM_DELAY_X32 = INSTRUCTION_DELAY_RAM_128MHZ,
|
||||
RAM_DELAY_X64 = INSTRUCTION_DELAY_RAM_256MHZ,
|
||||
RAM_DELAY_X128 = INSTRUCTION_DELAY_RAM_512MHZ,
|
||||
CPU_FREQUENCY_NORMAL = INSTRUCTION_EQUIV_FREQ_4MHZ,
|
||||
CPU_FREQUENCY_X2 = INSTRUCTION_EQUIV_FREQ_8MHZ,
|
||||
CPU_FREQUENCY_X4 = INSTRUCTION_EQUIV_FREQ_16MHZ,
|
||||
CPU_FREQUENCY_X8 = INSTRUCTION_EQUIV_FREQ_32MHZ,
|
||||
CPU_FREQUENCY_X16 = INSTRUCTION_EQUIV_FREQ_64MHZ,
|
||||
CPU_FREQUENCY_X32 = INSTRUCTION_EQUIV_FREQ_128MHZ,
|
||||
CPU_FREQUENCY_X64 = INSTRUCTION_EQUIV_FREQ_256MHZ,
|
||||
CPU_FREQUENCY_X128 = INSTRUCTION_EQUIV_FREQ_512MHZ,
|
||||
};
|
||||
#endif
|
||||
|
||||
// IOCTL commands. Passed from user space using the IOCTL method to command the driver to perform an action.
|
||||
#define IOCTL_CMD_Z80_STOP 's'
|
||||
#define IOCTL_CMD_Z80_START 'S'
|
||||
@@ -426,9 +572,12 @@ enum Z80_INSTRUCTION_DELAY {
|
||||
}\
|
||||
}
|
||||
#define resetZ80() {\
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||
setupMemory(Z80Ctrl->defaultPageMode);\
|
||||
if(Z80Ctrl->virtualDeviceBitMap & VIRTUAL_DEVICE_TZPU)\
|
||||
{\
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1); \
|
||||
udelay(2000);\
|
||||
}\
|
||||
z80_instant_reset(&Z80CPU);\
|
||||
}
|
||||
|
||||
@@ -460,10 +609,14 @@ enum Z80_MEMORY_PROFILE {
|
||||
};
|
||||
enum VIRTUAL_DEVICE {
|
||||
VIRTUAL_DEVICE_NONE = 0x00000000,
|
||||
VIRTUAL_DEVICE_MZ80A = 0x00000001,
|
||||
VIRTUAL_DEVICE_MZ700 = 0x00000002,
|
||||
VIRTUAL_DEVICE_MZ2000 = 0x00000004,
|
||||
VIRTUAL_DEVICE_PCW = 0x00000008,
|
||||
VIRTUAL_DEVICE_RFS40 = 0x01000000,
|
||||
VIRTUAL_DEVICE_RFS80 = 0x02000000,
|
||||
VIRTUAL_DEVICE_RFS = 0x03000000,
|
||||
VIRTUAL_DEVICE_TZPU = 0x04000000
|
||||
VIRTUAL_DEVICE_TZPU = 0x04000000,
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
@@ -524,14 +677,6 @@ typedef struct {
|
||||
uint8_t ioReadAhead;
|
||||
uint8_t ioWriteAhead;
|
||||
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
uint8_t lowMemorySwap;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
// MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
||||
uint8_t memSwitch;
|
||||
#endif
|
||||
|
||||
// Keyboard strobe and data. Required to detect hotkey press.
|
||||
uint8_t keyportStrobe;
|
||||
uint8_t keyportShiftCtrl;
|
||||
@@ -546,6 +691,7 @@ typedef struct {
|
||||
// is quicker than RAM (both are in the same kernel memory) as a pointer calculation needs to be made.
|
||||
uint32_t cpuGovernorDelayROM;
|
||||
uint32_t cpuGovernorDelayRAM;
|
||||
uint8_t governorSkip;
|
||||
|
||||
// An I/O processor, running as a User Space daemon, can register to receive signals and events.
|
||||
struct task_struct *ioTask;
|
||||
@@ -82,6 +82,14 @@
|
||||
#define CPLD_CMD_READIO_ADDR_P5 0x35
|
||||
#define CPLD_CMD_READIO_ADDR_P6 0x36
|
||||
#define CPLD_CMD_READIO_ADDR_P7 0x37
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR 0x38
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P1 0x39
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P2 0x3A
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P3 0x3B
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P4 0x3C
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P5 0x3D
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P6 0x3E
|
||||
#define CPLD_CMD_READIO_WRITE_ADDR_P7 0x3F
|
||||
#define CPLD_CMD_HALT 0x50
|
||||
#define CPLD_CMD_REFRESH 0x51
|
||||
#define CPLD_CMD_SET_SIGROUP1 0xF0
|
||||
@@ -130,7 +138,7 @@
|
||||
#define PAD_SPIO_2_ADDR 0x103C14
|
||||
#define PAD_SPIO_3_ADDR 0x103C16
|
||||
#define PAD_Z80IO_HIGH_BYTE_ADDR 0x1425
|
||||
#define PAD_Z80IO_READY_ADDR 0x103C18
|
||||
#define PAD_Z80IO_READY_ADDR 0x103C18 // GPIO12
|
||||
#define PAD_Z80IO_LTSTATE_ADDR 0x103C30 // GPIO47
|
||||
#define PAD_Z80IO_BUSRQ_ADDR 0x103C1A
|
||||
#define PAD_Z80IO_BUSACK_ADDR 0x103C1C
|
||||
@@ -386,8 +394,8 @@
|
||||
#define CPLD_LAST_TSTATE() (MHal_RIU_REG(PAD_Z80IO_LTSTATE_ADDR) & 0x4)
|
||||
#define CPLD_Z80_INT() (MHal_RIU_REG(PAD_Z80IO_INT_ADDR) & 0x4)
|
||||
#define CPLD_Z80_NMI() (MHal_RIU_REG(PAD_Z80IO_NMI_ADDR) & 0x4)
|
||||
#define SPI_SEND8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
#define SPI_SEND_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
@@ -396,9 +404,18 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND_I_8(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d_); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 1); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE);\
|
||||
}
|
||||
#define SPI_SEND16(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
@@ -406,10 +423,9 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
#define SPI_SEND_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
@@ -417,24 +433,63 @@
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND32i(_d_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
pr_info("Stage 0");\
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0);\
|
||||
pr_info("Stage 1");\
|
||||
#define SPI_SEND_P_16(_d1_) { uint32_t timeout = MAX_CHECK_CNT; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 2); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d1_); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) != 0);\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
pr_info("Stage 2");\
|
||||
timeout = MAX_CHECK_CNT; \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; }; \
|
||||
pr_info("Stage 3");\
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SET_FRAME_SIZE() { MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
}
|
||||
#define SPI_SEND32(_d_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)(_d_)); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)((_d_) >> 16)); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
}
|
||||
#define SPI_SEND_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
}
|
||||
#define SPI_SEND_I_32(_d1_, _d2_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 4); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
#define SPI_SEND_48(_d1_, _d2_, _d3_) { uint32_t timeout = MAX_CHECK_CNT*2; \
|
||||
MSPI_WRITE(MSPI_WBF_SIZE_OFFSET, 6); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET, (uint16_t)_d3_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+1, (uint16_t)_d2_); \
|
||||
MSPI_WRITE(MSPI_WRITE_BUF_OFFSET+2, (uint16_t)_d1_); \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_ENABLE); \
|
||||
while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };\
|
||||
MSPI_WRITE(MSPI_TRIGGER_OFFSET, MSPI_TRIGGER); \
|
||||
while((MSPI_READ(MSPI_DONE_OFFSET) & MSPI_DONE_FLAG) == 0) { if(--timeout == 0) break; } \
|
||||
MSPI_WRITE(MSPI_CHIP_SELECT_OFFSET, MSPI_CS8_DISABLE | MSPI_CS7_DISABLE | MSPI_CS6_DISABLE | MSPI_CS5_DISABLE | MSPI_CS4_DISABLE | MSPI_CS3_DISABLE | MSPI_CS2_DISABLE | MSPI_CS1_DISABLE); \
|
||||
MSPI_WRITE(MSPI_DONE_CLEAR_OFFSET, MSPI_CLEAR_DONE); \
|
||||
}
|
||||
|
||||
// while((MHal_RIU_REG(PAD_Z80IO_READY_ADDR) & 0x1) == 0) { if(--timeout == 0) break; };
|
||||
// read 2 byte
|
||||
#define MSPI_READ(_reg_) READ_WORD(gMspBaseAddr + ((_reg_)<<2))
|
||||
// write 2 byte
|
||||
@@ -54,7 +54,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
spinlock_t spinLock;
|
||||
unsigned long flags;
|
||||
|
||||
SPI_SEND8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||
SPI_SEND_8(CPLD_CMD_CLEAR_AUTO_REFRESH);
|
||||
|
||||
SPI_SEND32(0x00E30000 | (0x07 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
udelay(100);
|
||||
@@ -185,7 +185,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x10;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -223,7 +223,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
|
||||
// Read back the same byte.
|
||||
cmd = 0x20;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
while(CPLD_READY() == 0);
|
||||
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -254,7 +254,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x11;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -280,7 +280,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x21;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
while(CPLD_READY() == 0);
|
||||
result = READ_CPLD_DATA_IN();
|
||||
@@ -306,7 +306,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
}
|
||||
for(idx=0; idx < iterations; idx++)
|
||||
@@ -322,7 +322,7 @@ uint8_t z80io_Z80_TestMemory(void)
|
||||
} else
|
||||
{
|
||||
cmd = 0x19;
|
||||
SPI_SEND8(cmd);
|
||||
SPI_SEND_8(cmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
436
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
436
software/FusionX/src/z80drv/src/z80vhw_mz2000.c
Normal file
@@ -0,0 +1,436 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_mz2000.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - MZ-2000
|
||||
// This file contains the methods used to emulate the original Sharp MZ-2000 without
|
||||
// any additions, such as the RFS or TZFS boards.
|
||||
//
|
||||
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||
// and as such, they are included like header files rather than C linked object files.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
// Device constants.
|
||||
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||
|
||||
// System ROM's, either use the host machine ROM or preload a ROM image.
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-2000/ROMS/"
|
||||
#define ROM_IPL_ORIG_FILENAME ROM_DIR "mz2000_ipl.orig"
|
||||
|
||||
// Boot ROM rom load and size definitions.
|
||||
#define ROM_BOOT_LOAD_ADDR 0x000000
|
||||
#define ROM_BOOT_SIZE 0x800
|
||||
|
||||
// PCW control.
|
||||
typedef struct {
|
||||
uint8_t lowMemorySwap; // Boot mode lower memory is swapped to 0x8000:0xFFFF
|
||||
uint8_t highMemoryVRAM; // Flag to indicate high memory range 0xD000:0xFFFF is assigned to VRAM.
|
||||
uint8_t graphicsVRAM; // Flag to indicate graphics VRAM selected, default is character VRAM (0).
|
||||
uint8_t regCtrl; // Control register.
|
||||
} t_MZ2000Ctrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_MZ2000Ctrl MZ2000Ctrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect the PCW configuration.
|
||||
void mz2000SetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||
// memory can be mapped into the PCW memory address range.
|
||||
|
||||
// Setup defaults.
|
||||
MZ2000Ctrl.lowMemorySwap = 0x01; // Set memory swap flag to swapped, ie. IPL mode sees DRAM 0x0000:0x7FFF swapped to 0x8000:0xFFFF and ROM pages into 0x0000.
|
||||
MZ2000Ctrl.highMemoryVRAM = 0x00;
|
||||
MZ2000Ctrl.graphicsVRAM = 0x00;
|
||||
MZ2000Ctrl.regCtrl = 0x00;
|
||||
|
||||
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||
//
|
||||
if(mode == USE_PHYSICAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use physical RAM.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x8000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||
}
|
||||
else //if(idx >= 0x8000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
|
||||
// Video RAM labelled as HW as we dont want to cache it.
|
||||
//else if(idx >= 0xD000 && idx < 0xE000)
|
||||
// {
|
||||
// setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
//} else
|
||||
// {
|
||||
// setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
// }
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||
Z80Ctrl->refreshDRAM = 0;
|
||||
}
|
||||
else if(mode == USE_VIRTUAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use virtual RAM.
|
||||
// MZ-2000 comes up in IPL mode where lower 32K is ROM and upper 32K is RAM remapped from 0x0000.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x8000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (MZ2000Ctrl.lowMemorySwap ? idx - 0x8000 : idx));
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||
Z80Ctrl->refreshDRAM = 2;
|
||||
}
|
||||
|
||||
pr_info("MZ-2000 Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t mz2000LoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
long noBytes;
|
||||
struct file *fp;
|
||||
|
||||
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||
if(IS_ERR(fp))
|
||||
{
|
||||
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||
result = 1;
|
||||
} else
|
||||
{
|
||||
vfs_llseek(fp, 0, SEEK_SET);
|
||||
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||
}
|
||||
filp_close(fp,NULL);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||
void mz2000Init(uint8_t mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||
// when first powered on.
|
||||
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||
{
|
||||
// Lower memory is actually upper on startup, but ROM paged in, so set to zero.
|
||||
if(idx >= 0x0000 && idx < 0x8000)
|
||||
{
|
||||
Z80Ctrl->ram[idx+0x8000] = 0x00;
|
||||
} else
|
||||
// Lower memory is paged in at 0x8000:0xFFFF
|
||||
if(idx >= 0x8000 && idx < 0x10000)
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->ram[idx-0x8000] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->ram[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||
// such that the host behaves as per original spec.
|
||||
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||
{
|
||||
if(idx >= 0x0000 && idx < 0x8000)
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->rom[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// Initial memory config.
|
||||
mz2000SetupMemory(Z80Ctrl->defaultPageMode);
|
||||
|
||||
// mz2000LoadROM(ROM_IPL_ORIG_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_BOOT_SIZE);
|
||||
|
||||
pr_info("Enabling MZ-2000 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void mz2000Remove(void)
|
||||
{
|
||||
pr_info("Removing MZ-2000 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void mz2000DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Decoding memory address or I/O address?
|
||||
if(ioFlag == 0)
|
||||
{
|
||||
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||
//
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
// 8255 - Port A
|
||||
case IO_ADDR_E0:
|
||||
break;
|
||||
|
||||
// 8255 - Port B
|
||||
case IO_ADDR_E1:
|
||||
break;
|
||||
|
||||
// 8255 - Port C
|
||||
// Bit 3 - L = Reset and enter IPL mode.
|
||||
// Bit 1 - H = Set memory to normal state and reset cpu, RAM 0x0000:0xFFFF, L = no change.
|
||||
case IO_ADDR_E2:
|
||||
if(data & 0x01)
|
||||
data = 0x03;
|
||||
else if((data & 0x08) == 0)
|
||||
data = 0x06;
|
||||
else
|
||||
break;
|
||||
|
||||
// 8255 - Control Port
|
||||
// Bit 7 - H = Control word, L 3:1 define port C bit, bit 0 defines its state.
|
||||
case IO_ADDR_E3:
|
||||
//pr_info("E3:%02x\n", data);
|
||||
// Program control register.
|
||||
if(data & 0x80)
|
||||
{
|
||||
// Do nothing, this is the register which sets the 8255 mode.
|
||||
} else
|
||||
{
|
||||
switch((data >> 1) & 0x07)
|
||||
{
|
||||
// NST toggle.
|
||||
case 1:
|
||||
// NST pages in all RAM and resets cpu.
|
||||
if(data & 0x01)
|
||||
{
|
||||
MZ2000Ctrl.lowMemorySwap = 0;
|
||||
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(Z80Ctrl->defaultPageMode == USE_PHYSICAL_RAM)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
else
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
//resetZ80();
|
||||
}
|
||||
break;
|
||||
|
||||
// IPL start.
|
||||
case 3:
|
||||
// If IPL is active (L), reconfigure memory for power on state.
|
||||
if((data & 0x01) == 0)
|
||||
{
|
||||
mz2000SetupMemory(Z80Ctrl->defaultPageMode);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Port A - Z80 PIO, contains control bits affecting memory mapping.
|
||||
// Bit
|
||||
// 7 - Assign address range 0xD000:0xFFFF to V-RAM when H, when L assign RAM
|
||||
// 6 - Character VRAM (H), Graphics VRAM (L)
|
||||
// 4 - Change screen to 80 Char (H), 40 Char (L)
|
||||
// NB. When the VRAM is paged in, if Character VRAM is selected, range 0xD000:0xD7FF is VRAM, 0xC000:0xCFFF, 0xE000:0xFFFF is RAM.
|
||||
case IO_ADDR_E8:
|
||||
// High memory being assigned to VRAM or reverting?
|
||||
if(MZ2000Ctrl.highMemoryVRAM && (data & 0x80) == 0)
|
||||
{
|
||||
for(idx=0xC000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(Z80Ctrl->defaultPageMode == USE_PHYSICAL_RAM)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
} else
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (MZ2000Ctrl.lowMemorySwap ? idx - 0x8000 : idx));
|
||||
}
|
||||
}
|
||||
MZ2000Ctrl.highMemoryVRAM = 0;
|
||||
} else
|
||||
// If this is the first activation of the VRAM or the state of it changes, ie. character <-> graphics, then update the memory mapping.
|
||||
if( (!MZ2000Ctrl.highMemoryVRAM && (data & 0x80) != 0) || (MZ2000Ctrl.highMemoryVRAM && (MZ2000Ctrl.graphicsVRAM >> 6) != (data & 0x40)) )
|
||||
{
|
||||
for(idx=0xC000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
// Graphics RAM see's the entire range set to PHYSICAL, Character RAM only see's 0xD000:0xD7FF set to PHYSICAL.
|
||||
if( ((data & 0x40) && (idx >= 0xD000 && idx < 0xD800)) || ((data & 0x40) == 0) )
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
}
|
||||
MZ2000Ctrl.highMemoryVRAM = 1;
|
||||
}
|
||||
MZ2000Ctrl.graphicsVRAM = (data & 0x040) ? 1 : 0;
|
||||
break;
|
||||
|
||||
// Port is not a memory management port.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||
static inline uint8_t mz2000Read(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualMemory(address))
|
||||
{
|
||||
// Retrieve data from virtual memory.
|
||||
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
// Method to handle writes.
|
||||
static inline void mz2000Write(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
// uint32_t idx;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualRAM(address))
|
||||
{
|
||||
// Update virtual memory.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
481
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
481
software/FusionX/src/z80drv/src/z80vhw_mz700.c
Normal file
@@ -0,0 +1,481 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_mz700.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - MZ-700
|
||||
// This file contains the methods used to emulate the original Sharp MZ-700 without
|
||||
// any additions, such as the RFS or TZFS boards.
|
||||
//
|
||||
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||
// and as such, they are included like header files rather than C linked object files.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||
// Apr 2023 v1.1 - Updates from the PCW/MZ2000 changes.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
// Device constants.
|
||||
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||
|
||||
// PCW control.
|
||||
typedef struct {
|
||||
uint8_t regCtrl; // Control register.
|
||||
} t_MZ700Ctrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_MZ700Ctrl MZ700Ctrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect the PCW configuration.
|
||||
void mz700SetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||
// memory can be mapped into the PCW memory address range.
|
||||
|
||||
// Setup defaults.
|
||||
MZ700Ctrl.regCtrl = 0x00;
|
||||
|
||||
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||
//
|
||||
if(mode == USE_PHYSICAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use physical RAM.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x1000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||
}
|
||||
else if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
else if(idx >= 0xD000 && idx < 0xE000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
else if(idx >= 0xE000 && idx < 0xE800)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xE800 && idx < 0x10000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||
} else
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||
Z80Ctrl->refreshDRAM = 0;
|
||||
}
|
||||
else if(mode == USE_VIRTUAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use virtual RAM.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x1000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
else if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
else if(idx >= 0xD000 && idx < 0xE000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
else if(idx >= 0xE000 && idx < 0xE800)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xE800 && idx < 0xF000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
else if(idx >= 0xF000 && idx < 0x10000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||
Z80Ctrl->refreshDRAM = 2;
|
||||
}
|
||||
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
pr_info("MZ-700 Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t mz700LoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
long noBytes;
|
||||
struct file *fp;
|
||||
|
||||
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||
if(IS_ERR(fp))
|
||||
{
|
||||
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||
result = 1;
|
||||
} else
|
||||
{
|
||||
vfs_llseek(fp, 0, SEEK_SET);
|
||||
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||
}
|
||||
filp_close(fp,NULL);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||
void mz700Init(uint8_t mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||
// when first powered on.
|
||||
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||
{
|
||||
if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->ram[idx] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->ram[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||
// such that the host behaves as per original spec.
|
||||
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||
{
|
||||
// Copy BIOS and any add-on ROMS.
|
||||
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xE800 && idx < 0x10000))
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->rom[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
// Add in a test program to guage execution speed.
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
Z80Ctrl->ram[0x1200] = 0x01;
|
||||
Z80Ctrl->ram[0x1201] = 0x86;
|
||||
Z80Ctrl->ram[0x1202] = 0xf2;
|
||||
Z80Ctrl->ram[0x1203] = 0x3e;
|
||||
Z80Ctrl->ram[0x1204] = 0x15;
|
||||
Z80Ctrl->ram[0x1205] = 0x3d;
|
||||
Z80Ctrl->ram[0x1206] = 0x20;
|
||||
Z80Ctrl->ram[0x1207] = 0xfd;
|
||||
Z80Ctrl->ram[0x1208] = 0x0b;
|
||||
Z80Ctrl->ram[0x1209] = 0x78;
|
||||
Z80Ctrl->ram[0x120a] = 0xb1;
|
||||
Z80Ctrl->ram[0x120b] = 0x20;
|
||||
Z80Ctrl->ram[0x120c] = 0xf6;
|
||||
Z80Ctrl->ram[0x120d] = 0xc3;
|
||||
Z80Ctrl->ram[0x120e] = 0x00;
|
||||
Z80Ctrl->ram[0x120f] = 0x00;
|
||||
#endif
|
||||
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
pr_info("Enabling MZ-700 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void mz700Remove(void)
|
||||
{
|
||||
pr_info("Removing MZ-700 driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void mz700DecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Decoding memory address or I/O address?
|
||||
if(ioFlag == 0)
|
||||
{
|
||||
// #if(DEBUG_ENABLED & 1)
|
||||
// if(Z80Ctrl->debug >= 2)
|
||||
// {
|
||||
// pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
// }
|
||||
// #endif
|
||||
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||
//
|
||||
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||
// E000 - E003 : MZ80K/A/700 = 8255
|
||||
// E004 - E007 : MZ80K/A/700 = 8254
|
||||
// E008 - E00B : MZ80K/A/700 = LS367
|
||||
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||
// E014 : MZ80A/700 = Normat CRT display
|
||||
// E015 : MZ80A/700 = Reverse CRT display
|
||||
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// #if(DEBUG_ENABLED & 1)
|
||||
// if(Z80Ctrl->debug >= 2)
|
||||
// {
|
||||
// pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
// MZ700 memory mode switch.
|
||||
//
|
||||
// MZ-700
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM | |
|
||||
// OUT 0xE1 = | | |DRAM
|
||||
// OUT 0xE2 = |MONITOR | |
|
||||
// OUT 0xE3 = | | |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = | | |Inhibit
|
||||
// OUT 0xE6 = | | |<return>
|
||||
//
|
||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||
// Enable lower 4K block as DRAM
|
||||
case IO_ADDR_E0:
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||
case IO_ADDR_E1:
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
// MZ-700 mode we only work in first 64K block.
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable MOnitor ROM in lower 4K block
|
||||
case IO_ADDR_E2:
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||
case IO_ADDR_E3:
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Reset to power on condition memory map.
|
||||
case IO_ADDR_E4:
|
||||
// Lower 4K set to Monitor ROM.
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
// Upper 12K to hardware.
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||
case IO_ADDR_E5:
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||
}
|
||||
Z80Ctrl->inhibitMode = 1;
|
||||
break;
|
||||
|
||||
// Restore D000-FFFF to its original state.
|
||||
case IO_ADDR_E6:
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||
}
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
break;
|
||||
|
||||
// Port is not a memory management port.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||
static inline uint8_t mz700Read(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualMemory(address))
|
||||
{
|
||||
// Retrieve data from virtual memory.
|
||||
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
// Method to handle writes.
|
||||
static inline void mz700Write(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
// uint32_t idx;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualRAM(address))
|
||||
{
|
||||
// Update virtual memory.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
382
software/FusionX/src/z80drv/src/z80vhw_mz80a.c
Normal file
382
software/FusionX/src/z80drv/src/z80vhw_mz80a.c
Normal file
@@ -0,0 +1,382 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_mz80a.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - MZ-80A
|
||||
// This file contains the methods used to emulate the original Sharp MZ-80A without
|
||||
// any additions, such as the RFS or TZFS boards.
|
||||
//
|
||||
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||
// and as such, they are included like header files rather than C linked object files.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
// Device constants.
|
||||
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||
|
||||
// 40/80 Video Module control registers.
|
||||
//
|
||||
#define DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||
|
||||
// PCW control.
|
||||
typedef struct {
|
||||
// MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
||||
uint8_t memSwitch;
|
||||
|
||||
uint8_t regCtrl; // Control register.
|
||||
} t_MZ80ACtrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_MZ80ACtrl MZ80ACtrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect the PCW configuration.
|
||||
void mz80aSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Setup defaults.
|
||||
MZ80ACtrl.memSwitch = 0x00;
|
||||
MZ80ACtrl.regCtrl = 0x00;
|
||||
|
||||
// Setup default mode according to run mode, ie. Physical run or Virtual run.
|
||||
//
|
||||
if(mode == USE_PHYSICAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use physical RAM.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x1000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||
}
|
||||
else if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
else if(idx >= 0xD000 && idx < 0xE000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
else if(idx >= 0xE000 && idx < 0xE800)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xE800 && idx < 0x10000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_ROM, idx);
|
||||
} else
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
|
||||
// Cancel refresh as using physical RAM for program automatically refreshes DRAM.
|
||||
Z80Ctrl->refreshDRAM = 0;
|
||||
}
|
||||
else if(mode == USE_VIRTUAL_RAM)
|
||||
{
|
||||
// Initialise the page pointers and memory to use virtual RAM.
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0 && idx < 0x1000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
else if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
else if(idx >= 0xD000 && idx < 0xE000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
else if(idx >= 0xE000 && idx < 0xE800)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xE800 && idx < 0xF000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xF000 && idx < 0x10000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
|
||||
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||
Z80Ctrl->refreshDRAM = 2;
|
||||
}
|
||||
|
||||
// Original mode, ie. no virtual devices active, copy the host BIOS into the Virtual ROM and initialise remainder of ROM memory
|
||||
// such that the host behaves as per original spec.
|
||||
pr_info("Sync Host BIOS to virtual ROM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_ROM_SIZE; idx++)
|
||||
{
|
||||
if((idx >= 0x0000 && idx < 0x1000) || (idx >= 0xF000 && idx < 0x10000))
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->rom[idx] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->rom[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
pr_info("MZ-80A Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t mz80aLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
long noBytes;
|
||||
struct file *fp;
|
||||
|
||||
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||
if(IS_ERR(fp))
|
||||
{
|
||||
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||
result = 1;
|
||||
} else
|
||||
{
|
||||
vfs_llseek(fp, 0, SEEK_SET);
|
||||
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||
}
|
||||
filp_close(fp,NULL);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||
void mz80aInit(uint8_t mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Initialise the virtual RAM from the HOST DRAM. This is to maintain compatibility as some applications (in my experience) have
|
||||
// bugs, which Im putting down to not initialising variables. The host DRAM is in a pattern of 0x00..0x00, 0xFF..0xFF repeating
|
||||
// when first powered on.
|
||||
pr_info("Sync Host RAM to virtual RAM.\n");
|
||||
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||
{
|
||||
if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
SPI_SEND32((uint32_t)idx << 16 | CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->ram[idx] = z80io_PRL_Read8(1);
|
||||
} else
|
||||
{
|
||||
Z80Ctrl->ram[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
MZ80ACtrl.memSwitch = 0;
|
||||
|
||||
// If the 40/80 Video Module board is installed, ensure 40 character mode is selected.
|
||||
SPI_SEND_32(DSPCTL, CPLD_CMD_READ_ADDR);
|
||||
while(CPLD_READY() == 0);
|
||||
SPI_SEND_32(DSPCTL, CPLD_CMD_WRITE_ADDR);
|
||||
|
||||
pr_info("Enabling MZ-80A driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void mz80aRemove(void)
|
||||
{
|
||||
pr_info("Removing MZ-80A driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void mz80aDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Decoding memory address or I/O address?
|
||||
if(ioFlag == 0)
|
||||
{
|
||||
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||
//
|
||||
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||
// E000 - E003 : MZ80K/A/700 = 8255
|
||||
// E004 - E007 : MZ80K/A/700 = 8254
|
||||
// E008 - E00B : MZ80K/A/700 = LS367
|
||||
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||
// E014 : MZ80A/700 = Normat CRT display
|
||||
// E015 : MZ80A/700 = Reverse CRT display
|
||||
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||
switch(address)
|
||||
{
|
||||
// Memory map switch.
|
||||
case 0xE00C: case 0xE00D: case 0xE00E: case 0xE00F:
|
||||
if(readFlag)
|
||||
{
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
}
|
||||
MZ80ACtrl.memSwitch = 1;
|
||||
break;
|
||||
|
||||
// Reset memory map switch.
|
||||
case 0xE010: case 0xE011: case 0xE012: case 0xE013:
|
||||
if(readFlag)
|
||||
{
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (idx+0xC000));
|
||||
}
|
||||
}
|
||||
MZ80ACtrl.memSwitch = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
// Port is not a memory management port.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||
static inline uint8_t mz80aRead(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualMemory(address))
|
||||
{
|
||||
// Retrieve data from virtual memory.
|
||||
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return(data);
|
||||
}
|
||||
|
||||
// Method to handle writes.
|
||||
static inline void mz80aWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
// uint32_t idx;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
if(isVirtualRAM(address))
|
||||
{
|
||||
// Update virtual memory.
|
||||
writeVirtualRAM(address, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
379
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
379
software/FusionX/src/z80drv/src/z80vhw_pcw.c
Normal file
@@ -0,0 +1,379 @@
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Name: z80vhw_pcw.c
|
||||
// Created: Oct 2022
|
||||
// Author(s): Philip Smart
|
||||
// Description: Z80 Virtual Hardware Driver - Amstrad PCW-8xxx/PCW-9xxx
|
||||
// This file contains the methods used to emulate the Amstrad PCW specific
|
||||
// hardware.
|
||||
//
|
||||
// These drivers are intended to be instantiated inline to reduce overhead of a call
|
||||
// and as such, they are included like header files rather than C linked object files.
|
||||
// Credits:
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Mar 2023 v1.0 - Initial write based on the RFS hardware module.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// This source file 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 source file 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 <http://www.gnu.org/licenses/>.
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/device.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/mm.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/time.h>
|
||||
#include "z80io.h"
|
||||
|
||||
#include <gpio_table.h>
|
||||
#include <asm/io.h>
|
||||
#include <infinity2m/gpio.h>
|
||||
#include <infinity2m/registers.h>
|
||||
|
||||
// Device constants.
|
||||
#define RAM_BASE_ADDR 0x00000 // Base address of the 512K RAM.
|
||||
|
||||
// IO Ports.
|
||||
#define IO_FDC_STATUS 0x00 // NEC765 FDC Status Register.
|
||||
#define IO_FDC_DATA 0x01 // NEC765 FDC Data Register.
|
||||
#define IO_MEMBNK0 0xF0 // Memory bank 0000:3FFF register.
|
||||
#define IO_MEMBNK1 0xF1 // Memory bank 4000:7FFF register.
|
||||
#define IO_MEMBNK2 0xF2 // Memory bank 8000:BFFF register.
|
||||
#define IO_MEMBNK3 0xF3 // Memory bank C000:FFFF register.
|
||||
#define IO_MEMLOCK 0xF4 // CPC mode memory lock range.
|
||||
#define IO_ROLLERRAM 0xF5 // Set the Roller RAM address.
|
||||
#define IO_VORIGIN 0xF6 // Set screen vertical origin.
|
||||
#define IO_SCREENATTR 0xF7 // Set screen attributes.
|
||||
#define IO_GACMD 0xF8 // Gatearray command register.
|
||||
#define IO_GASTATUS 0xF8 // Gatearray status register.
|
||||
|
||||
// The boot code for the PCW-8256 is located within the printer controller. To avoid special hardware within the CPLD, this code is incorporated
|
||||
// into this module for rapid loading into RAM.
|
||||
#define ROM_DIR "/apps/FusionX/host/PCW/roms/"
|
||||
#define ROM_PCW8_BOOT_FILENAME ROM_DIR "PCW8256_boot.bin"
|
||||
#define ROM_PCW9_BOOT_FILENAME ROM_DIR "PCW9256_boot.bin"
|
||||
|
||||
// Boot ROM rom load and size definitions.
|
||||
#define ROM_BOOT_LOAD_ADDR 0x000000
|
||||
#define ROM_BOOT_SIZE 275
|
||||
|
||||
// PCW control.
|
||||
typedef struct {
|
||||
uint8_t regMemBank0; // Mirror of register F0, memory block select 0x0000-0x3FFF.
|
||||
uint8_t regMemBank1; // Mirror of register F1, memory block select 0x4000-0x7FFF.
|
||||
uint8_t regMemBank2; // Mirror of register F2, memory block select 0x8000-0xBFFF.
|
||||
uint8_t regMemBank3; // Mirror of register F3, memory block select 0xC000-0xFFFF.
|
||||
uint8_t regCPCPageMode; // Mirror of the CPC paging lock register F4.
|
||||
uint8_t regRollerRAM; // Mirror of Roller-RAM address register.
|
||||
uint8_t regCtrl; // Control register.
|
||||
} t_PCWCtrl;
|
||||
|
||||
// RFS Board control.
|
||||
static t_PCWCtrl PCWCtrl;
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
|
||||
// Method to setup the memory page config to reflect the PCW configuration.
|
||||
void pcwSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The PCW contains upto 512KB of standard RAM which can be expnded to a physical max of 2MB. The kernel malloc limit is 2MB so the whole virtual
|
||||
// memory can be mapped into the PCW memory address range.
|
||||
|
||||
// Setup defaults.
|
||||
PCWCtrl.regMemBank0 = 0x00;
|
||||
PCWCtrl.regMemBank1 = 0x01;
|
||||
PCWCtrl.regMemBank2 = 0x02;
|
||||
PCWCtrl.regMemBank3 = 0x03; // Keyboard is in locations 0x3FF0 - 0x3FFF of this memory block.
|
||||
PCWCtrl.regCPCPageMode = 0x00;
|
||||
PCWCtrl.regRollerRAM = 0x00;
|
||||
PCWCtrl.regCtrl = 0x00;
|
||||
|
||||
// Initialise the page pointers and memory to reflect a PCW, lower 128K is used by video logic so must always be accessed in hardware.
|
||||
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx >= 0x0000 && idx < 0xFFF0)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+idx));
|
||||
}
|
||||
if(idx >= 0xFFF0 && idx < 0x10000)
|
||||
{
|
||||
// The keyboard is memory mapped into upper bytes of block 3.
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, (RAM_BASE_ADDR+idx));
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
|
||||
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||
Z80Ctrl->refreshDRAM = 2;
|
||||
|
||||
// No I/O Ports on the RFS board.
|
||||
pr_info("PCW Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the RAM memory.
|
||||
//
|
||||
uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
long noBytes;
|
||||
struct file *fp;
|
||||
|
||||
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||
if(IS_ERR(fp))
|
||||
{
|
||||
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||
result = 1;
|
||||
} else
|
||||
{
|
||||
vfs_llseek(fp, 0, SEEK_SET);
|
||||
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->ram[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||
}
|
||||
filp_close(fp,NULL);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||
void pcwInit(uint8_t mode)
|
||||
{
|
||||
// Locals.
|
||||
//
|
||||
uint32_t idx;
|
||||
|
||||
// Clear memory as previous use or malloc can leave it randomly set.
|
||||
for(idx=0; idx < Z80_VIRTUAL_RAM_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->ram[idx] = 0x00;
|
||||
}
|
||||
|
||||
// Disable boot mode, we dont need to fetch the boot rom as we preload it.
|
||||
SPI_SEND32( (0x00F8 << 16) | (0x00 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
// Load boot ROM.
|
||||
loadROM(mode == 0 ? ROM_PCW8_BOOT_FILENAME : ROM_PCW9_BOOT_FILENAME, ROM_BOOT_LOAD_ADDR, ROM_BOOT_SIZE);
|
||||
|
||||
// Reset.
|
||||
//SPI_SEND32( (0x00F8 << 16) | (0x01 << 8) | CPLD_CMD_WRITEIO_ADDR);
|
||||
|
||||
// First two bytes to NULL as were not using the bootstrap and normal operations after bootstrap would disable the mode.
|
||||
Z80Ctrl->ram[0] = 0x00;
|
||||
Z80Ctrl->ram[1] = 0x00;
|
||||
|
||||
pr_info("Enabling PCW-%s driver.\n", mode == 0 ? "8256" : "9256");
|
||||
return;
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void pcwRemove(void)
|
||||
{
|
||||
pr_info("Removing PCW driver.\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to decode an address and make any system memory map changes as required.
|
||||
//
|
||||
static inline void pcwDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// IO Switch.
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address&0xff)
|
||||
{
|
||||
case IO_FDC_STATUS:
|
||||
//pr_info("FDC_STATUS:%02x\n", data);
|
||||
break;
|
||||
|
||||
case IO_FDC_DATA:
|
||||
//pr_info("FDC_DATA:%02x\n", data);
|
||||
break;
|
||||
|
||||
case IO_MEMBNK0:
|
||||
if(!readFlag)
|
||||
{
|
||||
PCWCtrl.regMemBank0 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank0;
|
||||
pr_info("Setting Bank 0:%02x\n", PCWCtrl.regMemBank0);
|
||||
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType((idx+0x0000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank0 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank0*16384)+idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_MEMBNK1:
|
||||
if(!readFlag)
|
||||
{
|
||||
PCWCtrl.regMemBank1 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank1;
|
||||
pr_info("Setting Bank 1:%02x\n", PCWCtrl.regMemBank1);
|
||||
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType((idx+0x4000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank1 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank1*16384)+idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_MEMBNK2:
|
||||
if(!readFlag)
|
||||
{
|
||||
PCWCtrl.regMemBank2 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank2;
|
||||
pr_info("Setting Bank 2:%02x\n", PCWCtrl.regMemBank2);
|
||||
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType((idx+0x8000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank2 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank2*16384)+idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_MEMBNK3:
|
||||
if(!readFlag)
|
||||
{
|
||||
PCWCtrl.regMemBank3 = (data & 0x80) ? data & 0x7f : PCWCtrl.regMemBank3;
|
||||
pr_info("Setting Bank 3:%02x\n", PCWCtrl.regMemBank3);
|
||||
for(idx=0x0000; idx < 0x4000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(idx < 0x3FF0)
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, PCWCtrl.regMemBank3 >= 8 ? MEMORY_TYPE_VIRTUAL_RAM : MEMORY_TYPE_PHYSICAL_RAM_WT, (RAM_BASE_ADDR+(PCWCtrl.regMemBank3*16384)+idx));
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_MEMLOCK:
|
||||
if(!readFlag)
|
||||
{
|
||||
pr_info("MEMLOCK:%02x\n", data);
|
||||
PCWCtrl.regCPCPageMode = data;
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_ROLLERRAM:
|
||||
if(!readFlag)
|
||||
{
|
||||
pr_info("********RollerRAM********:%02x => %04x\n", data, (((data >> 5)&0x7) * 16384)+((data&0x1f)*512));
|
||||
PCWCtrl.regRollerRAM = data;
|
||||
}
|
||||
break;
|
||||
|
||||
case IO_VORIGIN:
|
||||
pr_info("VORIGIN:%02x\n", data);
|
||||
break;
|
||||
case IO_SCREENATTR:
|
||||
pr_info("SCREENATTR:%02x\n", data);
|
||||
break;
|
||||
case IO_GACMD:
|
||||
pr_info("GACMD:%02x\n", data);
|
||||
break;
|
||||
|
||||
default:
|
||||
pr_info("Unknown:ADDR:%02x,%02x\n", address&0xff, data);
|
||||
break;
|
||||
}
|
||||
} else
|
||||
// Memory map switch.
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Method to read from either the memory mapped registers if enabled else the RAM.
|
||||
static inline uint8_t pcwRead(zuint16 address, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t data = 0xFF;
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
// Return the contents of the ROM at given address.
|
||||
data = isVirtualROM(address) ? readVirtualROM(address) : readVirtualRAM(address);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if(DEBUG_ENABLED & 1)
|
||||
if(Z80Ctrl->debug >= 3) pr_info("PCW-Read:%04x, BK0:%02x, BK1:%02x, BK2:%02x, BK3:%02x, CTRL:%02x\n", address, PCWCtrl.regMemBank0, PCWCtrl.regMemBank1, PCWCtrl.regMemBank2, PCWCtrl.regMemBank3, PCWCtrl.regCtrl);
|
||||
#endif
|
||||
return(data);
|
||||
}
|
||||
|
||||
// Method to handle writes.
|
||||
static inline void pcwWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
{
|
||||
// Locals.
|
||||
// uint32_t idx;
|
||||
|
||||
|
||||
// I/O Operation?
|
||||
if(ioFlag)
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
{
|
||||
switch(address)
|
||||
{
|
||||
default:
|
||||
// Any unprocessed write is commited to RAM.
|
||||
writeVirtualRAM(address, data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
#if(DEBUG_ENABLED & 1)
|
||||
if(Z80Ctrl->debug >= 3) pr_info("PCW-Write:%04x, BK0:%02x, BK1:%02x, BK2:%02x, BK3:%02x, CTRL:%02x\n", address, PCWCtrl.regMemBank0, PCWCtrl.regMemBank1, PCWCtrl.regMemBank2, PCWCtrl.regMemBank3, PCWCtrl.regCtrl);
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
@@ -67,6 +67,10 @@
|
||||
#define BNKSELUSER 0xEFFE // Select RFS Bank2 (User ROM)
|
||||
#define BNKCTRL 0xEFFF // Bank Control register (read/write).
|
||||
|
||||
// 40/80 Video Module control registers.
|
||||
//
|
||||
#define DSPCTL 0xDFFF // Display 40/80 select register (bit 7)
|
||||
|
||||
//
|
||||
// RFS v2 Control Register constants.
|
||||
//
|
||||
@@ -87,7 +91,13 @@
|
||||
#define BNKCTRLDEF BBMOSI+SDCS+BBCLK // Default on startup for the Bank Control register.
|
||||
|
||||
// RFS Board ROM rom filename definitions.
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-80A/RFS/"
|
||||
#elif(TARGET_HOST_MZ700 == 1)
|
||||
#define ROM_DIR "/apps/FusionX/host/MZ-700/RFS/"
|
||||
#else
|
||||
#error "Unknown host configured."
|
||||
#endif
|
||||
#define ROM_MROM_40C_FILENAME ROM_DIR "MROM_256_40c.bin"
|
||||
#define ROM_USER_I_40C_FILENAME ROM_DIR "USER_ROM_256_40c.bin"
|
||||
#define ROM_USER_II_40C_FILENAME ROM_DIR "USER_ROM_II_256_40c.bin"
|
||||
@@ -167,6 +177,7 @@ typedef struct {
|
||||
uint8_t upCntr; // Register enable up counter.
|
||||
uint32_t mromAddr; // Actual address in MROM of active bank.
|
||||
uint32_t uromAddr; // Actual address in UROM of active bank.
|
||||
uint8_t memSwitch; // MZ-80A can relocate the lower 4K ROM by swapping RAM at 0xC000.
|
||||
t_SDCtrl sd; // SD Control.
|
||||
} t_RFSCtrl;
|
||||
|
||||
@@ -194,7 +205,7 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
RFSCtrl.regCtrl = 0x00;
|
||||
RFSCtrl.mromAddr = MROM_ADDR;
|
||||
RFSCtrl.uromAddr = USER_ROM_I_ADDR;
|
||||
Z80Ctrl->memSwitch = 0;
|
||||
RFSCtrl.memSwitch = 0;
|
||||
RFSCtrl.sd.trainingCnt = 0;
|
||||
RFSCtrl.sd.initialised = 0;
|
||||
RFSCtrl.sd.dataOutFlag = 0;
|
||||
@@ -214,7 +225,19 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
}
|
||||
if(idx >= 0xE800 && idx < 0xF000)
|
||||
else if(idx >= 0x1000 && idx < 0xD000)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
else if(idx >= 0xD000 && idx < 0xE000)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
else if(idx >= 0xE000 && idx < 0xE800)
|
||||
{
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
else if(idx >= 0xE800 && idx < 0xF000)
|
||||
{
|
||||
// Memory is both ROM and hardware, the registers share the same address space.
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM | MEMORY_TYPE_VIRTUAL_HW, (RFSCtrl.uromAddr+(idx-0xE800)));
|
||||
@@ -224,6 +247,18 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
setMemoryType((idx/MEMORY_BLOCK_GRANULARITY), MEMORY_TYPE_VIRTUAL_ROM, (idx+(Z80_VIRTUAL_ROM_SIZE - 0x10000)));
|
||||
}
|
||||
}
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
|
||||
// Enable refresh as using virtual RAM stops refresh of host DRAM.
|
||||
Z80Ctrl->refreshDRAM = 2;
|
||||
|
||||
#if (TARGET_HOST_MZ700 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
#endif
|
||||
|
||||
// No I/O Ports on the RFS board.
|
||||
pr_info("RFS Memory Setup complete.\n");
|
||||
@@ -231,7 +266,7 @@ void rfsSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
|
||||
// Method to load a ROM image into the ROM memory.
|
||||
//
|
||||
uint8_t loadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
uint8_t rfsLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
@@ -264,10 +299,10 @@ void rfsInit(uint8_t mode80c)
|
||||
uint32_t idx;
|
||||
|
||||
// Load ROMS according to the display configuration, 40 char = standard, 80 char = 40/80 board installed.
|
||||
loadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
loadROM(mode80c == 0 ? ROM_USER_I_40C_FILENAME : ROM_USER_I_80C_FILENAME, ROM_USER_I_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
loadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
loadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
rfsLoadROM(mode80c == 0 ? ROM_MROM_40C_FILENAME : ROM_MROM_80C_FILENAME, ROM_MROM_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
rfsLoadROM(mode80c == 0 ? ROM_USER_I_40C_FILENAME : ROM_USER_I_80C_FILENAME, ROM_USER_I_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
rfsLoadROM(mode80c == 0 ? ROM_USER_II_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_II_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
rfsLoadROM(mode80c == 0 ? ROM_USER_III_40C_FILENAME : ROM_USER_II_80C_FILENAME, ROM_USER_III_LOAD_ADDR, ROM_MROM_SIZE);
|
||||
|
||||
// Copy the Floppy ROM to the top portion of ROM. USER III isnt normally used and if it is, 4K will be free.
|
||||
for(idx=0xF000; idx < 0x10000; idx++)
|
||||
@@ -276,7 +311,13 @@ void rfsInit(uint8_t mode80c)
|
||||
while(CPLD_READY() == 0);
|
||||
Z80Ctrl->rom[idx+(Z80_VIRTUAL_ROM_SIZE-0x10000)] = z80io_PRL_Read8(1);
|
||||
}
|
||||
pr_info("Enabling RFS driver.\n");
|
||||
|
||||
#if (TARGET_HOST_MZ700 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
#endif
|
||||
|
||||
pr_info("Enabling RFS(%d) driver.\n", mode80c == 1 ? 80 : 40);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -304,7 +345,7 @@ static inline void rfsDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
}
|
||||
Z80Ctrl->memSwitch = 0x01;
|
||||
RFSCtrl.memSwitch = 0x01;
|
||||
}
|
||||
|
||||
// Reset memory map switch.
|
||||
@@ -318,7 +359,7 @@ static inline void rfsDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t
|
||||
setMemoryType((idx+0xC000)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, (0xC000+idx));
|
||||
}
|
||||
}
|
||||
Z80Ctrl->memSwitch = 0x00;
|
||||
RFSCtrl.memSwitch = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -755,7 +796,7 @@ static inline void rfsWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
// Update memory map to reflect register change.
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
if(Z80Ctrl->memSwitch)
|
||||
if(RFSCtrl.memSwitch)
|
||||
{
|
||||
// Monitor ROM is located at 0xC000.
|
||||
setMemoryType((0xC000+idx)/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, (RFSCtrl.mromAddr+idx));
|
||||
@@ -17,6 +17,7 @@
|
||||
// Copyright: (c) 2019-2023 Philip Smart <philip.smart@net2net.org>
|
||||
//
|
||||
// History: Feb 2023 v1.0 - Initial write based on the tranZPUter SW hardware.
|
||||
// Apr 2023 v1.1 - Updates & bug fixes.
|
||||
//
|
||||
// Notes: See Makefile to enable/disable conditional components
|
||||
//
|
||||
@@ -72,6 +73,9 @@ typedef struct {
|
||||
// TZPU Board control.
|
||||
static t_TZPUCtrl TZPUCtrl;
|
||||
|
||||
// Forward prototypes.
|
||||
static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag);
|
||||
|
||||
//-------------------------------------------------------------------------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
@@ -115,15 +119,145 @@ static t_TZPUCtrl TZPUCtrl;
|
||||
// 30 - All memory and IO are on the tranZPUter board, 64K block 6 selected.
|
||||
// 31 - All memory and IO are on the tranZPUter board, 64K block 7 selected.
|
||||
|
||||
// Method to setup the memory page config to reflect installation of a tranZPUter SW Board. This sets up the default
|
||||
// as the memory map changes according to selection and handled in-situ.
|
||||
void tzpuSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The tranZPUter SW uses a CPLD to set a 4K Z80 memory range window into a 512K-1MB linear RAM block. The actual map required
|
||||
// at any one time is governed by the Memory Config register at I/O port 0x60.
|
||||
// This method sets the initial state, which is a normal Sharp operating mode, all memory and IO (except tranZPUter
|
||||
// control IO block) are on the mainboard.
|
||||
|
||||
// Setup defaults.
|
||||
TZPUCtrl.clkSrc = 0x00; // Clock defaults to host.
|
||||
TZPUCtrl.regCmd = 0x00; // Default for the CPLD Command.
|
||||
TZPUCtrl.regCmdStatus = 0x00; // Default for the CPLD Command Status.
|
||||
TZPUCtrl.regCpuCfg = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||
TZPUCtrl.regCpuInfo = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||
// Setup the CPLD status value, this is used by the host for configuration of tzfs.
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ80A;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ700;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ2000;
|
||||
#endif
|
||||
TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed.
|
||||
|
||||
// Default memory mode, TZFS.
|
||||
Z80Ctrl->memoryMode = TZMM_ORIG;
|
||||
|
||||
// Reset IO mapping.
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx++)
|
||||
{
|
||||
Z80Ctrl->iopage[idx] = idx | IO_TYPE_PHYSICAL_HW;
|
||||
}
|
||||
|
||||
// I/O Ports on the tranZPUter SW board. All hosts have the same ports for the tzpu board.
|
||||
for(idx=0x0000; idx < IO_PAGE_SIZE; idx+=0x0100)
|
||||
{
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CTRLLATCH] = IO_TZ_CTRLLATCH | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SETXMHZ] = IO_TZ_SETXMHZ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SET2MHZ] = IO_TZ_SET2MHZ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CLKSELRD] = IO_TZ_CLKSELRD | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SVCREQ] = IO_TZ_SVCREQ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SYSREQ] = IO_TZ_SYSREQ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCMD] = IO_TZ_CPLDCMD | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDSTATUS] = IO_TZ_CPLDSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUCFG] = IO_TZ_CPUCFG | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUSTATUS] = IO_TZ_CPUSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUINFO] = IO_TZ_CPUINFO | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCFG] = IO_TZ_CPLDCFG | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDINFO] = IO_TZ_CPLDINFO | IO_TYPE_VIRTUAL_HW;
|
||||
}
|
||||
|
||||
#if (TARGET_HOST_MZ700 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
#endif
|
||||
|
||||
pr_info("TZPU Memory Setup complete.\n");
|
||||
}
|
||||
|
||||
// Method to load a ROM image into the ROM memory.
|
||||
//
|
||||
uint8_t tzpuLoadROM(const char* romFileName, uint32_t loadAddr, uint32_t loadSize)
|
||||
{
|
||||
// Locals.
|
||||
uint8_t result = 0;
|
||||
long noBytes;
|
||||
struct file *fp;
|
||||
|
||||
fp = filp_open(romFileName, O_RDONLY, 0);
|
||||
if(IS_ERR(fp))
|
||||
{
|
||||
pr_info("Error opening ROM Image:%s\n:", romFileName);
|
||||
result = 1;
|
||||
} else
|
||||
{
|
||||
vfs_llseek(fp, 0, SEEK_SET);
|
||||
noBytes = kernel_read(fp, fp->f_pos, &Z80Ctrl->rom[loadAddr], loadSize);
|
||||
if(noBytes < loadSize)
|
||||
{
|
||||
// pr_info("Short load, ROM Image:%s, bytes loaded:%08x\n:", romFileName, loadSize);
|
||||
}
|
||||
filp_close(fp,NULL);
|
||||
}
|
||||
|
||||
return(result);
|
||||
}
|
||||
|
||||
// Perform any setup operations, such as variable initialisation, to enable use of this module.
|
||||
void tzpuInit(void)
|
||||
{
|
||||
// Setup all initial TZFS memory modes
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_ORIG, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS2, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS3, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS4, 1);
|
||||
|
||||
// Ensure memory configuration is correct before requesting K64F to load Bios.
|
||||
tzpuSetupMemory(USE_VIRTUAL_RAM);
|
||||
|
||||
// Default memory mode, TZFS.
|
||||
Z80Ctrl->memoryMode = TZMM_TZFS;
|
||||
|
||||
#if (TARGET_HOST_MZ700 == 1)
|
||||
// Reset memory paging to default.
|
||||
SPI_SEND_32(0x00e4, 0x00 << 8 | CPLD_CMD_WRITEIO_ADDR);
|
||||
#endif
|
||||
|
||||
// New memory maps setup, perform a reset so that the K64F CPU loads the required ROMS.
|
||||
sendSignal(Z80Ctrl->ioTask, SIGUSR1);
|
||||
|
||||
pr_info("Enabling TZPU driver.\n");
|
||||
}
|
||||
|
||||
// Perform any de-initialisation when the driver is removed.
|
||||
void tzpuRemove(void)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// Go through and clear all memory maps, leave the original page in slot 0.
|
||||
for(idx=1; idx < MEMORY_MODES; idx++)
|
||||
{
|
||||
if(Z80Ctrl->page[idx] != NULL)
|
||||
{
|
||||
kfree(Z80Ctrl->page[idx]);
|
||||
Z80Ctrl->page[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Default memory mode, ORIG.
|
||||
Z80Ctrl->memoryMode = TZMM_ORIG;
|
||||
|
||||
pr_info("Removing TZPU driver.\n");
|
||||
return;
|
||||
}
|
||||
@@ -133,27 +267,154 @@ void tzpuRemove(void)
|
||||
static inline void tzpuDecodeMemoryMapSetup(zuint16 address, zuint8 data, uint8_t ioFlag, uint8_t readFlag)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// I/O or Memory?
|
||||
if(ioFlag == 0)
|
||||
{
|
||||
// Memory map switch.
|
||||
if(readFlag == 0)
|
||||
// #if(DEBUG_ENABLED & 1)
|
||||
// if(Z80Ctrl->debug >= 2)
|
||||
// {
|
||||
// pr_info("MEM:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
// }
|
||||
// #endif
|
||||
// Certain machines have memory mapped I/O, these need to be handled in-situ as some reads may change the memory map.
|
||||
// These updates are made whilst waiting for the CPLD to retrieve the requested byte.
|
||||
//
|
||||
// 0000 - 0FFF : MZ80K/A/700 = Monitor ROM or RAM (MZ80A rom swap)
|
||||
// 1000 - CFFF : MZ80K/A/700 = RAM
|
||||
// C000 - CFFF : MZ80A = Monitor ROM (MZ80A rom swap)
|
||||
// D000 - D7FF : MZ80K/A/700 = VRAM
|
||||
// D800 - DFFF : MZ700 = Colour VRAM (MZ700)
|
||||
// E000 - E003 : MZ80K/A/700 = 8255
|
||||
// E004 - E007 : MZ80K/A/700 = 8254
|
||||
// E008 - E00B : MZ80K/A/700 = LS367
|
||||
// E00C - E00F : MZ80A = Memory Swap (MZ80A)
|
||||
// E010 - E013 : MZ80A = Reset Memory Swap (MZ80A)
|
||||
// E014 : MZ80A/700 = Normat CRT display
|
||||
// E015 : MZ80A/700 = Reverse CRT display
|
||||
// E200 - E2FF : MZ80A/700 = VRAM roll up/roll down.
|
||||
// E800 - EFFF : MZ80K/A/700 = User ROM socket or DD Eprom (MZ700)
|
||||
// F000 - F7FF : MZ80K/A/700 = Floppy Disk interface.
|
||||
// F800 - FFFF : MZ80K/A/700 = Floppy Disk interface.
|
||||
switch(address)
|
||||
{
|
||||
|
||||
} else
|
||||
{
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else
|
||||
// I/O Decoding.
|
||||
{
|
||||
// Only lower 8 bits recognised in the tzpu.
|
||||
switch(address & 0xFF)
|
||||
// #if(DEBUG_ENABLED & 1)
|
||||
// if(Z80Ctrl->debug >= 2)
|
||||
// {
|
||||
// pr_info("IO:%04x,%02x,%d,%d\n", address, data, ioFlag, readFlag);
|
||||
// }
|
||||
// #endif
|
||||
|
||||
// Determine if this is a memory management port and update the memory page if required.
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
default:
|
||||
// MZ700 memory mode switch.
|
||||
//
|
||||
// MZ-700
|
||||
// |0000:0FFF|1000:CFFF|D000:FFFF
|
||||
// ------------------------------
|
||||
// OUT 0xE0 = |DRAM | |
|
||||
// OUT 0xE1 = | | |DRAM
|
||||
// OUT 0xE2 = |MONITOR | |
|
||||
// OUT 0xE3 = | | |Memory Mapped I/O
|
||||
// OUT 0xE4 = |MONITOR |DRAM |Memory Mapped I/O
|
||||
// OUT 0xE5 = | | |Inhibit
|
||||
// OUT 0xE6 = | | |<return>
|
||||
//
|
||||
// <return> = Return to the state prior to the complimentary command being invoked.
|
||||
// Enable lower 4K block as DRAM
|
||||
case IO_ADDR_E0:
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable upper 12K block, including Video/Memory Mapped peripherals area, as DRAM.
|
||||
case IO_ADDR_E1:
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
// MZ-700 mode we only work in first 64K block.
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_RAM, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable MOnitor ROM in lower 4K block
|
||||
case IO_ADDR_E2:
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
break;
|
||||
|
||||
// Enable Video RAM and Memory mapped peripherals in upper 12K block.
|
||||
case IO_ADDR_E3:
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Reset to power on condition memory map.
|
||||
case IO_ADDR_E4:
|
||||
// Lower 4K set to Monitor ROM.
|
||||
for(idx=0x0000; idx < 0x1000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_VIRTUAL_ROM, idx);
|
||||
}
|
||||
if(!Z80Ctrl->inhibitMode)
|
||||
{
|
||||
// Upper 12K to hardware.
|
||||
for(idx=0xD000; idx < 0xE000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_VRAM, idx);
|
||||
}
|
||||
for(idx=0xE000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_PHYSICAL_HW, idx);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// Inhibit. Backup current page data in region 0xD000-0xFFFF and inhibit it.
|
||||
case IO_ADDR_E5:
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
backupMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||
setMemoryType(idx/MEMORY_BLOCK_GRANULARITY, MEMORY_TYPE_INHIBIT, idx);
|
||||
}
|
||||
Z80Ctrl->inhibitMode = 1;
|
||||
break;
|
||||
|
||||
// Restore D000-FFFF to its original state.
|
||||
case IO_ADDR_E6:
|
||||
for(idx=0xD000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
restoreMemoryType(idx/MEMORY_BLOCK_GRANULARITY);
|
||||
}
|
||||
Z80Ctrl->inhibitMode = 0;
|
||||
break;
|
||||
|
||||
// Port is not a memory management port.
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -252,7 +513,9 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
switch(address & 0x00FF)
|
||||
{
|
||||
case IO_TZ_CTRLLATCH:
|
||||
//pr_info("CTRLLATCH:%02x\n", data);
|
||||
#if(DEBUG_ENABLED & 0x01)
|
||||
if(Z80Ctrl->debug >=3) pr_info("CTRLLATCH:%02x\n", data);
|
||||
#endif
|
||||
|
||||
// Check to see if the memory mode page has been allocated for requested mode, if it hasnt, we need to allocate and then define.
|
||||
Z80Ctrl->memoryMode = (data & (MEMORY_MODES - 1));
|
||||
@@ -264,13 +527,13 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
(Z80Ctrl->page[Z80Ctrl->memoryMode]) = (uint32_t *)kmalloc((MEMORY_BLOCK_SLOTS*sizeof(uint32_t)), GFP_KERNEL);
|
||||
if ((Z80Ctrl->page[Z80Ctrl->memoryMode]) == NULL)
|
||||
{
|
||||
pr_info("z80drv: failed to allocate memory mapping page:%d memory!", Z80Ctrl->memoryMode);
|
||||
pr_info("z80drv: failed to allocate memory mapping page:%d memory!", Z80Ctrl->memoryMode);
|
||||
Z80Ctrl->page[Z80Ctrl->memoryMode] = Z80Ctrl->page[0];
|
||||
}
|
||||
|
||||
// A lot of the memory maps below are identical, minor changes such as RAM bank. This is a direct conversion of the VHDL code from the CPLD.
|
||||
//
|
||||
for(idx=0x0000; idx < 0x10000; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
for(idx=0x0000; idx < MEMORY_PAGE_SIZE; idx+=MEMORY_BLOCK_GRANULARITY)
|
||||
{
|
||||
switch(Z80Ctrl->memoryMode)
|
||||
{
|
||||
@@ -744,71 +1007,3 @@ static inline void tzpuWrite(zuint16 address, zuint8 data, uint8_t ioFlag)
|
||||
return;
|
||||
}
|
||||
|
||||
// Method to setup the memory page config to reflect installation of a tranZPUter SW Board. This sets up the default
|
||||
// as the memory map changes according to selection and handled in-situ.
|
||||
void tzpuSetupMemory(enum Z80_MEMORY_PROFILE mode)
|
||||
{
|
||||
// Locals.
|
||||
uint32_t idx;
|
||||
|
||||
// The tranZPUter SW uses a CPLD to set a 4K Z80 memory range window into a 512K-1MB linear RAM block. The actual map required
|
||||
// at any one time is governed by the Memory Config register at I/O port 0x60.
|
||||
// This method sets the initial state, which is a normal Sharp operating mode, all memory and IO (except tranZPUter
|
||||
// control IO block) are on the mainboard.
|
||||
|
||||
// Setup defaults.
|
||||
TZPUCtrl.clkSrc = 0x00; // Clock defaults to host.
|
||||
TZPUCtrl.regCmd = 0x00; // Default for the CPLD Command.
|
||||
TZPUCtrl.regCmdStatus = 0x00; // Default for the CPLD Command Status.
|
||||
TZPUCtrl.regCpuCfg = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||
TZPUCtrl.regCpuInfo = 0x00; // Not used, as no FPGA available, but need to store/return value if addressed.
|
||||
// Setup the CPLD status value, this is used by the host for configuration of tzfs.
|
||||
#if(TARGET_HOST_MZ80A == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ80A;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ700 == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ700;
|
||||
#endif
|
||||
#if(TARGET_HOST_MZ2000 == 1)
|
||||
TZPUCtrl.regCpldInfo = (CPLD_VERSION << 4) | (CPLD_HAS_FPGA_VIDEO << 3) | HWMODE_MZ2000;
|
||||
#endif
|
||||
TZPUCtrl.regCpldCfg = 0x00; // Not used, as no CPLD available, but need to store/return value if addressed.
|
||||
|
||||
// Go through and clear all memory maps, valid for startup and reset.
|
||||
for(idx=0; idx < MEMORY_MODES; idx++)
|
||||
{
|
||||
if(Z80Ctrl->page[idx] != NULL)
|
||||
{
|
||||
kfree(Z80Ctrl->page[idx]);
|
||||
Z80Ctrl->page[idx] = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// Setup all initial TZFS memory modes
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_ORIG, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS2, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS3, 1);
|
||||
tzpuWrite(IO_TZ_CTRLLATCH, TZMM_TZFS4, 1);
|
||||
Z80Ctrl->memoryMode = 0x02; // Default memory mode, MZ-80A.
|
||||
|
||||
// I/O Ports on the tranZPUter SW board. All hosts have the same ports for the tzpu board.
|
||||
for(idx=0x0000; idx < 0x10000; idx+=0x0100)
|
||||
{
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CTRLLATCH] = IO_TZ_CTRLLATCH | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SETXMHZ] = IO_TZ_SETXMHZ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SET2MHZ] = IO_TZ_SET2MHZ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CLKSELRD] = IO_TZ_CLKSELRD | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SVCREQ] = IO_TZ_SVCREQ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_SYSREQ] = IO_TZ_SYSREQ | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCMD] = IO_TZ_CPLDCMD | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDSTATUS] = IO_TZ_CPLDSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUCFG] = IO_TZ_CPUCFG | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUSTATUS] = IO_TZ_CPUSTATUS | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPUINFO] = IO_TZ_CPUINFO | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDCFG] = IO_TZ_CPLDCFG | IO_TYPE_VIRTUAL_HW;
|
||||
Z80Ctrl->iopage[idx+IO_TZ_CPLDINFO] = IO_TZ_CPLDINFO | IO_TYPE_VIRTUAL_HW;
|
||||
}
|
||||
|
||||
pr_info("TZPU Memory Setup complete.\n");
|
||||
}
|
||||
Reference in New Issue
Block a user