summaryrefslogtreecommitdiff
path: root/stm32/z80-if.c
diff options
context:
space:
mode:
Diffstat (limited to 'stm32/z80-if.c')
-rw-r--r--stm32/z80-if.c607
1 files changed, 607 insertions, 0 deletions
diff --git a/stm32/z80-if.c b/stm32/z80-if.c
new file mode 100644
index 0000000..a8083c8
--- /dev/null
+++ b/stm32/z80-if.c
@@ -0,0 +1,607 @@
+/*
+
+PC14 af1 OSC32
+PC15 " "
+PA9 af1 USART1_TX
+PA10 af1 USART1_RX
+
+
+JTDO remap PB3, SPI1_SCK'
+NJTRST remap PB4, SPI1_MISO'
+PB5 remap SPI1_MOSI'
+JTDI remap PA15, SPI1_NSS'
+
+AFIO_MAPR2 =
+AFIO_MAPR_SWJ_CFG_JTAG_OFF_SW_ON (frees
+AFIO_MAPR_SPI1_REMAP
+
+*/
+
+#include <libopencm3/stm32/gpio.h>
+#include <libopencm3/stm32/rcc.h>
+#include <libopencm3/stm32/timer.h>
+#include <libopencm3/stm32/dma.h>
+#include "z80-if.h"
+
+/* Number of array elements */
+#define NELEMS(x) (sizeof x/sizeof *x)
+
+#define ODR 0x0c
+#define IDR 0x08
+
+#define CONCAT(x,y) x ## y
+#define EVALUATOR(x,y) CONCAT(x,y)
+
+#define GPIO_(X) CONCAT(GPIO, X)
+
+/*
+
+ A0 A 1 P O
+ A1 A 2 P O
+ A2 A 3 P O
+ A3 A 4 P O
+ A4 A 5 P O
+ A5 A 6 P O
+ A6 A 7 P O
+ A7 A 8 O
+ A8 C 0 P O
+ A9 C 1 P O
+ A10 C 2 P O
+ A11 C 3 P O
+ A12 C 4 P O
+ A13 C 5 P O
+ A14 C 6 O
+ A15 C 7 O
+ A16 C 10 O
+ A17 C 11 O
+ A18 C 12 O
+
+ D0 B 8 I/O
+ D1 B 9 I/O
+ D2 B 10 I/O
+ D3 B 11 I/O
+ D4 B 12 I/O
+ D5 B 13 I/O
+ D6 B 14 I/O
+ D7 B 15 I/O
+
+ ME C 13 P O
+ RD B 0 P O
+ WR B 1 P O
+
+ BUSREQ D 2 O
+ BUSACK A 11 I
+// HALT A 12 I
+ IOE A 12 I TIM1_ETR
+ NMI B 7 O
+ RST B 6 O TIM16_CH1N
+
+*/
+
+#define P_ME GPIOC
+#define ME 13
+#define P_RD GPIOB
+#define RD 0
+#define P_WR GPIOB
+#define WR 1
+#define P_BUSREQ GPIOD
+#define BUSREQ 2
+#define P_BUSACK GPIOA
+#define BUSACK 11
+//#define P_HALT GPIOA
+//#define HALT 12
+#define P_IOE GPIOA
+#define IOE 12
+#define P_NMI GPIOB
+#define NMI 7
+#define P_RST GPIOB
+#define RST 6
+
+#define ADp1_OFS 0
+#define ADp1_WIDTH 8
+#define ADp1_SHIFT 1
+#define ADp1_PORT GPIOA
+
+#define ADp2_OFS ADp1_WIDTH
+#define ADp2_WIDTH 8
+#define ADp2_SHIFT 0
+#define ADp2_PORT GPIOC
+
+#define ADp3_OFS (ADp2_OFS+ADp2_WIDTH)
+#define ADp3_WIDTH 3
+#define ADp3_SHIFT 10
+#define ADp3_PORT GPIOC
+
+#define ADunbuff1_WIDTH 1
+#define ADunbuff1_SHIFT 8
+#define ADunbuff1_PORT GPIOA
+
+#define ADunbuff2_WIDTH 2
+#define ADunbuff2_SHIFT 6
+#define ADunbuff2_PORT GPIOC
+
+#define ADunbuff3_WIDTH 3
+#define ADunbuff3_SHIFT 10
+#define ADunbuff3_PORT GPIOC
+
+#define DB_OFS 0
+#define DB_WIDTH 8
+#define DB_SHIFT 8
+#define DB_PORT GPIOB
+
+#define GPIO_ME GPIO_(ME)
+#define GPIO_RD GPIO_(RD)
+#define GPIO_WR GPIO_(WR)
+#define GPIO_BUSREQ GPIO_(BUSREQ)
+#define GPIO_BUSACK GPIO_(BUSACK)
+//#define GPIO_HALT GPIO_(HALT)
+#define GPIO_IOE GPIO_(IOE)
+#define GPIO_NMI GPIO_(NMI)
+#define GPIO_RST GPIO_(RST)
+
+#define Z80_O_ME BBIO_PERIPH(P_ME+ODR, ME)
+#define Z80_O_RD BBIO_PERIPH(P_RD+ODR, RD)
+#define Z80_O_WR BBIO_PERIPH(P_WR+ODR, WR)
+#define Z80_O_BUSREQ BBIO_PERIPH(P_BUSREQ+ODR, BUSREQ)
+#define Z80_O_NMI BBIO_PERIPH(P_NMI+ODR, NMI)
+#define Z80_O_RST BBIO_PERIPH(P_RST+ODR, RST)
+
+#define Z80_I_BUSACK BBIO_PERIPH(P_BUSACK+IDR, BUSACK)
+//#define Z80_I_HALT BBIO_PERIPH(P_HALT+IDR, HALT)
+
+
+#define MASK(n) ((1<<n)-1)
+
+#define IOFIELD_SET(src, ofs, width, shift) \
+ ((((src>>ofs) & MASK(width)) << shift) | ((((~src>>ofs) & MASK(width)) << shift) << 16))
+
+#define IOFIELD_GET(src, width, shift) \
+ ((src>>shift) & MASK(width))
+
+#define CNF_MODE_I_F (GPIO_CNF_INPUT_FLOAT<<2 |GPIO_MODE_INPUT)
+#define CNF_MODE_O_PP (GPIO_CNF_OUTPUT_PUSHPULL<<2 | GPIO_MODE_OUTPUT_10_MHZ)
+
+#define DB_MODE_INPUT ( (CNF_MODE_I_F << (4 * 0)) \
+ | (CNF_MODE_I_F << (4 * 1)) \
+ | (CNF_MODE_I_F << (4 * 2)) \
+ | (CNF_MODE_I_F << (4 * 3)) \
+ | (CNF_MODE_I_F << (4 * 4)) \
+ | (CNF_MODE_I_F << (4 * 5)) \
+ | (CNF_MODE_I_F << (4 * 6)) \
+ | (CNF_MODE_I_F << (4 * 7)))
+
+#define DB_MODE_OUTPUT ( (CNF_MODE_O_PP << (4 * 0)) \
+ | (CNF_MODE_O_PP << (4 * 1)) \
+ | (CNF_MODE_O_PP << (4 * 2)) \
+ | (CNF_MODE_O_PP << (4 * 3)) \
+ | (CNF_MODE_O_PP << (4 * 4)) \
+ | (CNF_MODE_O_PP << (4 * 5)) \
+ | (CNF_MODE_O_PP << (4 * 6)) \
+ | (CNF_MODE_O_PP << (4 * 7)))
+
+
+/*--------------------------------------------------------------------------*/
+
+volatile uint8_t z80_inbuf[256];
+static uint32_t inbuf_ndt;
+
+/*--------------------------------------------------------------------------*/
+
+#define TIM16_BDTR TIM_BDTR(TIM16)
+
+static void tim16_setup(void)
+{
+ RCC_APB2RSTR |= (1<<17);
+ RCC_APB2RSTR &= ~(1<<17);
+
+ TIM16_BDTR = TIM_BDTR_MOE;
+
+ TIM16_CCMR1 = 0
+ | TIM_CCMR1_OC1M_FORCE_LOW
+ /* | TIM_CCMR1_OC1M_FORCE_HIGH */
+ /* | TIM_CCMR1_OC1M_PWM2 */
+
+ /* | TIM_CCMR1_OC1PE */
+ /* | TIM_CCMR1_OC1FE */
+ | TIM_CCMR1_CC1S_OUT;
+
+ TIM16_CCER = TIM_CCER_CC1NE
+ | TIM_CCER_CC1NP;
+
+ TIM16_ARR = 48; /* default */
+ TIM16_CCR1 = 1; /* */
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void tim1_setup(void)
+{
+ RCC_APB2RSTR |= RCC_APB2RSTR_TIM1RST;
+ RCC_APB2RSTR &= ~RCC_APB2RSTR_TIM1RST;
+
+ TIM1_CR1 = 0;
+
+ TIM1_SMCR = 0
+ /* | TIM_SMCR_ETP */
+ /* | TIM_SMCR_ETF_CK_INT_N_2 */
+ | TIM_SMCR_TS_ETRF
+ | TIM_SMCR_SMS_OFF
+ ;
+
+ TIM1_DIER = TIM_DIER_TDE;
+
+
+ TIM1_CCMR1 = 0
+ | TIM_CCMR1_OC1M_FORCE_LOW
+ /* | TIM_CCMR1_OC1M_FORCE_HIGH */
+ /* | TIM_CCMR1_OC1M_PWM2 */
+
+ /* | TIM_CCMR1_OC1PE */
+ /* | TIM_CCMR1_OC1FE */
+ | TIM_CCMR1_CC1S_OUT;
+
+ TIM1_SMCR |= TIM_SMCR_SMS_TM;
+ /* | TIM_SMCR_SMS_ECM1 */
+}
+
+/*--------------------------------------------------------------------------*/
+
+static void dma4_setup(void)
+{
+ DMA1_CCR4 =
+ DMA_CCR_PL_VERY_HIGH
+ | DMA_CCR_MSIZE_8BIT
+ | DMA_CCR_PSIZE_8BIT
+ | DMA_CCR_MINC
+ | DMA_CCR_CIRC;
+
+ DMA1_CMAR4 = (uint32_t) &z80_inbuf[0];
+
+#if (DB_SHIFT == 0) || (DB_SHIFT == 8)
+ DMA1_CPAR4 = DB_PORT + IDR + DB_SHIFT/8;
+#else
+ #error "Databus not byte aligned!"
+#endif
+
+ DMA1_CNDTR4 = inbuf_ndt = NELEMS(z80_inbuf);
+
+ DMA1_CCR4 |= DMA_CCR_EN;
+}
+
+/*--------------------------------------------------------------------------*/
+
+void tim16_set(int mode)
+{
+ uint16_t cc_mode;
+
+ cc_mode = TIM_CCMR1_CC1S_OUT;
+
+ TIM16_CR1 = TIM_CR1_OPM;
+
+ if (mode < 0)
+ cc_mode |= TIM_CCMR1_OC1M_FORCE_LOW;
+ else if (mode == 0)
+ cc_mode |= TIM_CCMR1_OC1M_FORCE_HIGH;
+ else {
+ TIM16_ARR = mode;
+ cc_mode |= TIM_CCMR1_OC1M_PWM2;
+ }
+
+ TIM16_CCMR1 = cc_mode;
+
+ if (mode > 0)
+ TIM16_CR1 |= TIM_CR1_CEN;
+}
+
+/*--------------------------------------------------------------------------*/
+
+
+
+/*
+ * A0..A6, A8..A13 are buffered. No need to disable.
+ * A7, A14..A18: set to input.
+ */
+
+static void z80_setup_adrbus_tristate(void)
+{
+#if 0
+ gpio_set_mode(ADunbuff1_PORT, GPIO_MODE_INPUT,
+ GPIO_CNF_INPUT_FLOAT, MASK(ADunbuff1_WIDTH) << ADunbuff1_SHIFT);
+ gpio_set_mode(ADunbuff2_PORT, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT,
+ (MASK(ADunbuff2_WIDTH) << ADunbuff2_SHIFT) | (MASK(ADunbuff3_WIDTH) << ADunbuff3_SHIFT));
+#else
+ GPIO_CRH(GPIOA) = (GPIO_CRH(GPIOA) & ~(0x0f << (4 * 0)))
+ | (CNF_MODE_I_F << (4 * 0));
+ GPIO_CRL(GPIOC) = (GPIO_CRL(GPIOC) & ~((0x0f << (4 * 6)) | (0x0f << (4 * 7))))
+ | ((CNF_MODE_I_F << (4 * 6)) | (CNF_MODE_I_F << (4 * 7)));
+ GPIO_CRH(GPIOC) = (GPIO_CRH(GPIOC) & ~((0x0f << (4*2)) | (0x0f << (4*3)) | (0x0f << (4*4))))
+ | ((CNF_MODE_I_F << (4*2)) | (CNF_MODE_I_F << (4*3)) | (CNF_MODE_I_F << (4*4)));
+#endif
+}
+
+
+static void z80_setup_adrbus_active(void)
+{
+#if 0
+ gpio_set_mode(ADunbuff1_PORT, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADunbuff1_WIDTH) << ADunbuff1_SHIFT);
+ gpio_set_mode(ADunbuff2_PORT, GPIO_MODE_OUTPUT_10_MHZ, GPIO_CNF_OUTPUT_PUSHPULL,
+ (MASK(ADunbuff2_WIDTH) << ADunbuff2_SHIFT) | (MASK(ADunbuff3_WIDTH) << ADunbuff3_SHIFT));
+#else
+ GPIO_CRH(GPIOA) = (GPIO_CRH(GPIOA) & ~(0x0f << (4 * 0)))
+ | (CNF_MODE_O_PP << (4 * 0));
+ GPIO_CRL(GPIOC) = (GPIO_CRL(GPIOC) & ~((0x0f << (4 * 6)) | (0x0f << (4 * 7))))
+ | ((CNF_MODE_O_PP << (4 * 6)) | (CNF_MODE_O_PP << (4 * 7)));
+ GPIO_CRH(GPIOC) = (GPIO_CRH(GPIOC) & ~((0x0f << (4*2)) | (0x0f << (4*3)) | (0x0f << (4*4))))
+ | ((CNF_MODE_O_PP << (4*2)) | (CNF_MODE_O_PP << (4*3)) | (CNF_MODE_O_PP << (4*4)));
+#endif
+}
+
+
+static void z80_setup_dbus_in(void)
+{
+ GPIO_CRH(DB_PORT) = DB_MODE_INPUT;
+}
+
+static void z80_setup_dbus_out(void)
+{
+ GPIO_CRH(DB_PORT) = DB_MODE_OUTPUT;
+}
+
+
+static void z80_setaddress(uint32_t addr)
+{
+ GPIO_BSRR(ADp1_PORT) = IOFIELD_SET(addr, ADp1_OFS, ADp1_WIDTH, ADp1_SHIFT);
+ GPIO_BSRR(ADp2_PORT) = IOFIELD_SET(addr, ADp2_OFS, ADp2_WIDTH, ADp2_SHIFT);
+ GPIO_BSRR(ADp3_PORT) = IOFIELD_SET(addr, ADp3_OFS, ADp3_WIDTH, ADp3_SHIFT);
+}
+
+void z80_setup_bus(void)
+{
+ tim16_setup();
+ tim1_setup();
+ dma4_setup();
+
+ gpio_set_mode(P_RST, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_RST);
+ Z80_O_BUSREQ = 1;
+ gpio_set_mode(P_BUSREQ, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO_BUSREQ);
+ Z80_O_NMI = 1;
+ gpio_set_mode(P_NMI, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO_NMI);
+ Z80_O_ME = 1;
+ Z80_O_RD = 1;
+ Z80_O_WR = 1;
+ gpio_set_mode(P_ME, GPIO_MODE_OUTPUT_2_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO_ME);
+ gpio_set_mode(P_RD, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, GPIO_RD | GPIO_WR);
+
+ gpio_set_mode(P_BUSACK, GPIO_MODE_INPUT,
+ GPIO_CNF_INPUT_FLOAT, GPIO_BUSACK | GPIO_IOE);
+
+ //Z80_O_BUSREQ = 0;
+ //while(Z80_I_BUSACK == 1);
+
+ gpio_set_mode(ADp1_PORT, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp1_WIDTH) << ADp1_SHIFT);
+ gpio_set_mode(ADp2_PORT, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp2_WIDTH) << ADp2_SHIFT);
+ gpio_set_mode(ADp3_PORT, GPIO_MODE_OUTPUT_10_MHZ,
+ GPIO_CNF_OUTPUT_PUSHPULL, MASK(ADp3_WIDTH) << ADp3_SHIFT);
+
+ z80_setup_dbus_in();
+}
+
+void z80_get_bus(void)
+{
+ Z80_O_BUSREQ = 0;
+ while(Z80_I_BUSACK == 1);
+ z80_setup_adrbus_active();
+}
+
+void z80_release_bus(void)
+{
+ z80_setup_dbus_in();
+ z80_setup_adrbus_tristate();
+ Z80_O_BUSREQ = 1;
+ while(Z80_I_BUSACK == 0);
+}
+
+void z80_reset(level_t level)
+{
+ int x = level ? -1 : 0;
+
+ tim16_set(x);
+
+// Z80_O_RST = level;
+}
+
+void z80_reset_pulse(void)
+{
+ tim16_set(48);
+}
+
+void z80_busreq(level_t level)
+{
+ Z80_O_BUSREQ = level;
+}
+
+#if 0
+int z80_stat_halt(void)
+{
+ return Z80_I_HALT;
+}
+#endif
+
+void z80_write(uint32_t addr, uint8_t data)
+{
+ z80_setaddress(addr);
+ Z80_O_ME = 0;
+ GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT);
+ z80_setup_dbus_out();
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ Z80_O_ME = 1;
+}
+
+uint8_t z80_read(uint32_t addr)
+{
+ uint8_t data;
+
+ z80_setaddress(addr);
+ Z80_O_ME = 0;
+ z80_setup_dbus_in();
+ Z80_O_RD = 0;
+ Z80_O_RD = 0;
+ data = IOFIELD_GET(GPIO_IDR(DB_PORT),DB_WIDTH, DB_SHIFT);
+ Z80_O_RD = 1;
+ Z80_O_ME = 1;
+
+ return data;
+}
+
+
+void z80_memset(uint32_t addr, uint8_t data, int length)
+{
+ z80_setup_dbus_out();
+ Z80_O_ME = 0;
+ while(length--) {
+ z80_setaddress(addr++);
+ GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT);
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ }
+ Z80_O_ME = 1;
+}
+
+void z80_write_block(uint8_t *src, uint32_t dest, uint32_t length)
+{
+ uint8_t data;
+
+ z80_setup_dbus_out();
+ Z80_O_ME = 0;
+ while(length--) {
+ z80_setaddress(dest++);
+ data = *src++;
+ GPIO_BSRR(DB_PORT) = IOFIELD_SET(data, DB_OFS, DB_WIDTH, DB_SHIFT);
+ Z80_O_WR = 0;
+ Z80_O_WR = 1;
+ }
+ Z80_O_ME = 1;
+}
+
+/*
+ 0179' rx.bs_mask: ds 1 ; (buf_len - 1)
+ 017A' rx.in_idx: ds 1 ;
+ 017B' rx.out_idx: ds 1 ;
+ 017C' rx.buf: ds rx.buf_len ;
+ 018B' rx.buf_end equ $-1 ; last byte (start+len-1)
+
+ 018C' tx.bs_mask: ds 1 ; (buf_len - 1)
+ 018D' tx.in_idx: ds 1 ;
+ 018E' tx.out_idx: ds 1 ;
+ 018F' tx.buf: ds tx.buf_len ;
+ 019E' tx.buf_end equ $-1 ; last byte
+*/
+
+#define fifo_bufsize_mask -3
+#define fifo_index_in -2
+#define fifo_index_out -1
+
+#if 1
+
+static struct {
+ uint32_t base;
+ uint8_t idx_out,
+ idx_in,
+ mask;
+ } fifos[2];
+
+void z80_fifo_init(void)
+{
+ z80_get_bus();
+ fifos[fifo_in].base = tx_fifo;
+ fifos[fifo_in].idx_out = z80_read(tx_fifo+fifo_index_out);
+ fifos[fifo_in].idx_in = z80_read(tx_fifo+fifo_index_in);
+ fifos[fifo_in].mask = z80_read(tx_fifo+fifo_bufsize_mask);
+
+ fifos[fifo_out].base = rx_fifo;
+ fifos[fifo_out].idx_out = z80_read(rx_fifo+fifo_index_out);
+ fifos[fifo_out].idx_in = z80_read(rx_fifo+fifo_index_in);
+ fifos[fifo_out].mask = z80_read(rx_fifo+fifo_bufsize_mask);
+ z80_release_bus();
+}
+#endif
+
+int z80_fifo_is_not_empty(fifo_t f)
+{
+ uint32_t adr = fifos[f].base+fifo_index_in;
+ uint8_t idx;
+
+ z80_get_bus();
+ idx = z80_read(adr);
+ z80_release_bus();
+
+ return idx != fifos[f].idx_out;
+}
+
+int z80_fifo_is_not_full(fifo_t f)
+{
+ int rc;
+
+ z80_get_bus();
+ rc = ((fifos[f].idx_in + 1) & fifos[f].mask)
+ != z80_read(fifos[f].base+fifo_index_out);
+ z80_release_bus();
+
+ return rc;
+}
+
+uint8_t z80_fifo_getc(fifo_t f)
+{
+ uint8_t rc, idx;
+
+ while (!z80_fifo_is_not_empty(f))
+ ;
+
+ z80_get_bus();
+ idx = fifos[f].idx_out;
+ rc = z80_read(fifos[f].base+idx);
+ fifos[f].idx_out = ++idx & fifos[f].mask;
+ z80_write(fifos[f].base+fifo_index_out, fifos[f].idx_out);
+ z80_release_bus();
+
+ return rc;
+}
+
+
+void z80_fifo_putc(fifo_t f, uint8_t val)
+{
+ int idx;
+
+ while (!z80_fifo_is_not_full(f))
+ ;
+
+ z80_get_bus();
+ idx = fifos[f].idx_in;
+ z80_write(fifos[f].base+idx, val);
+ fifos[f].idx_in = ++idx & fifos[f].mask;
+ z80_write(fifos[f].base+fifo_index_in, fifos[f].idx_in);
+ z80_release_bus();
+}
+
+int z80_inbuf_getc(void)
+{
+ int c = -1;
+
+ if (inbuf_ndt != DMA1_CNDTR4) {
+ c = z80_inbuf[NELEMS(z80_inbuf) - inbuf_ndt--];
+ if (inbuf_ndt == 0)
+ inbuf_ndt = NELEMS(z80_inbuf);
+ }
+
+ return c;
+}
+