From 3c1c8415713f80cd0919f7bd5244d292f1c3cfe1 Mon Sep 17 00:00:00 2001 From: Thomas Albers Date: Tue, 8 Aug 2023 18:52:32 +0200 Subject: Initial commit --- .gitignore | 2 + Makefile | 41 +++++++ README.org | 19 ++++ crc16.c | 48 ++++++++ crt0.asm | 93 +++++++++++++++ zbootloader.c | 361 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ zbootloader.h | 58 ++++++++++ zeta.h | 153 +++++++++++++++++++++++++ 8 files changed, 775 insertions(+) create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 README.org create mode 100644 crc16.c create mode 100644 crt0.asm create mode 100644 zbootloader.c create mode 100644 zbootloader.h create mode 100644 zeta.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..980bd99 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +build +bootloader.hex diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..bd309f5 --- /dev/null +++ b/Makefile @@ -0,0 +1,41 @@ +ASM=crt0.asm +SRC=crc16.c zbootloader.c + +OBJ=$(ASM:%.asm=build/%.rel) $(SRC:%.c=build/%.rel) +IHX=build/bootloader.ihx +TARGET=bootloader.hex + +CFLAGS=-mz80 -I. --Werror +LDFLAGS=-mz80 --no-std-crt0 --code-loc 0x100 --data-loc 0x8000 -Wl-b_GSINIT=0x80 + +ROM_CHIP=SST39SF020A + +all : $(TARGET) + +build/%.rel : %.asm + @echo ' (AS)' $< + @sdcpp -P -I. -DASSEMBLY $< > build/$< + @sdasz80 -g -o $@ build/$< + +build/%.rel : %.c + @echo ' (CC)' $< + @sdcc $(CFLAGS) -c -o $@ $< + +$(IHX) : $(OBJ) + @echo ' (LD)' $(OBJ) + @sdcc $(LDFLAGS) -o $@ $(OBJ) + +$(TARGET) : $(IHX) + @hex2bin.py $< $@ + +.PHONY : upload +upload : + z80up $(TARGET) -p /dev/ttyUSB0 + +.PHONE : flash +flash : + minipro -y -sp $(ROM_CHIP) -w $(TARGET) + +.PHONY : clean +clean : + @rm -rf build/* $(TARGET) diff --git a/README.org b/README.org new file mode 100644 index 0000000..a4d4f3e --- /dev/null +++ b/README.org @@ -0,0 +1,19 @@ +#+title: Zbootloader +#+author: Thomas Albers Raviola + +Bootloader for Z80 based computers enables uploading programs to memory through +serial communication and accesing both memory and I/O addresses from the +terminal + +* Protocol + + +| Z80 | Master | +|----------+----------| +| | Header | +| ACK | | +| | Argument | +| ACK | | +| Response | | +| | ACK | +|----------+----------| diff --git a/crc16.c b/crc16.c new file mode 100644 index 0000000..68b7a96 --- /dev/null +++ b/crc16.c @@ -0,0 +1,48 @@ +#include + +static const uint16_t crc_table[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, + 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6, + 0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485, + 0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4, + 0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC, + 0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B, + 0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12, + 0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A, + 0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41, + 0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49, + 0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70, + 0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78, + 0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F, + 0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E, + 0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D, + 0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C, + 0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3, + 0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A, + 0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92, + 0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9, + 0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1, + 0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8, + 0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0 +}; + +uint16_t +crc16(const void *buf, size_t len) +{ + const uint8_t *p = buf; + + uint16_t crc = 0; + while (len--) + crc = crc_table[(crc >> 8) ^ (*p++)] ^ (crc << 8); + + return crc; +} diff --git a/crt0.asm b/crt0.asm new file mode 100644 index 0000000..567ab47 --- /dev/null +++ b/crt0.asm @@ -0,0 +1,93 @@ +#include + + .module crt0 + .globl _main + + .area _HEADER (ABS) + ;; Reset vector + .org 0x0000 + ld SP, #0x00 + xor A + ld I, A + jp init + ;; ISR table + .org 0x0010 +_ctc0_isr_ptr: + .dw #0 +_ctc1_isr_ptr: + .dw #0 +_ctc2_isr_ptr: + .dw #0 + .globl _ctc3_isr_ptr +_ctc3_isr_ptr: + .dw #_ctc3_isr + .globl _rx_isr_ptr +_rx_isr_ptr: + .dw #_rx_isr + ;; Init code +init: + xor A + ;; Enable extended memory + out (WIN_0_CTRL), A + ld A, #0b00100000 + out (WIN_1_CTRL), A + ld A, #0b01000000 + out (WIN_2_CTRL), A + ld A, #0b01100000 + out (WIN_3_CTRL), A + + ld A, #SREG_EXT_MEM + out (SREG_CTRL), A + + call gsinit + call _main +1$: + halt + jr 1$ + + ;; Ordering of segments for the linker. + .area _HOME + .area _CODE + .area _INITIALIZER + .area _GSINIT + .area _GSFINAL + + .area _DATA + .area _INITIALIZED + .area _BSEG + .area _BSS + .area _HEAP + + .area _CODE + + .area _GSINIT +gsinit: + ;; Default-initialized global variables. + ld bc, #l__DATA + ld a, b + or a, c + jr Z, zeroed_data + ld hl, #s__DATA + ld (hl), #0x00 + dec bc + ld a, b + or a, c + jr Z, zeroed_data + ld e, l + ld d, h + inc de + ldir +zeroed_data: + ;; Explicitly initialized global variables. + ld bc, #l__INITIALIZER + ld a, b + or a, c + jr Z, gsinit_next + ld de, #s__INITIALIZED + ld hl, #s__INITIALIZER + ldir + +gsinit_next: + + .area _GSFINAL + ret diff --git a/zbootloader.c b/zbootloader.c new file mode 100644 index 0000000..df168df --- /dev/null +++ b/zbootloader.c @@ -0,0 +1,361 @@ +#include +#include +#include +#include + +/* volatile uint8_t rx_head = 0; */ +/* volatile uint8_t rx_tail = 0; */ +/* volatile uint8_t rx_fifo[FIFO_LEN]; */ + +struct fifo { + uint8_t head; + uint8_t tail; + uint8_t data[FIFO_LEN]; +}; + +volatile struct fifo rx_fifo = {0, 0, {0}}; + +uint8_t +fifo_pop(struct fifo *fifo) +{ + uint8_t ret = fifo->data[fifo->head]; + if (++fifo->head >= LEN(fifo->data)) + fifo->head = 0; + return ret; +} + +void +fifo_push(struct fifo *fifo, uint8_t v) +{ + fifo->data[fifo->tail] = v; + + if (++fifo->tail >= LEN(fifo->data)) + fifo->tail = 0; +} + +bool +fifo_empty(const struct fifo *fifo) +{ + return (fifo->head == fifo->tail); +} + +void +fifo_clear(struct fifo *fifo) +{ + fifo->head = 0; + fifo->tail = 0; +} + +static const uint8_t sio_a_cfg[] = { + 0b00011000, // Reset channel + 4 , // wr4 + 0b00000100, // X1 clock, one stop bit, no parity + 1 , // wr1 + SIO_RX_INT_MD0 | SIO_RX_INT_MD1, // interrupt on every Rx, no wait function + 3 , // wr3 + 0b11000001, // enable Rx - 8 bit char + 5 , // wr5 + 0b01101000 // enable Tx - 8 bit char +}; + +extern void *rx_isr_ptr; +extern void *ctc0_isr_ptr; +extern void *ctc1_isr_ptr; +extern void *ctc2_isr_ptr; +extern void *ctc3_isr_ptr; + +#define ISR_OFFSET(x) ((unsigned int)&x) + +static const unsigned char sio_b_cfg[] = { + 0b00011000, // Reset channel + 2 , // load interrupt vector + ISR_OFFSET(rx_isr_ptr) // int_table_rx +}; + +/* int_table: */ +/* int_table_rx: */ +/* dw rx_isr */ + +void +rx_isr(void) __critical __interrupt(0) +{ + fifo_push(&rx_fifo, sio_a_data); +} + +static volatile uint32_t millis = 0; + +void +ctc3_isr(void) __critical __interrupt(1) +{ + millis += 5; +} + +uint32_t +clock(void) +{ + volatile uint32_t ret; + DI; + ret = millis; + EI; + return ret; +} + +void +putbyte(unsigned char b) +{ + unsigned char ctrl = 0; + + sio_a_data = b; + + while (!(ctrl & 0x04)) { + sio_a_ctrl = 0; + ctrl = sio_a_ctrl; + } +} + +static volatile int32_t errno = 0; + +uint8_t +getbyte(void) +{ + uint8_t b; + uint32_t ms = clock(); + errno = 0; + while (fifo_empty(&rx_fifo)) { + if (clock() - ms > TIMEOUT_MS) { + errno = ERR_TIMEOUT; + return 0; + } + } + DI; + b = fifo_pop(&rx_fifo); + EI; + return b; +} + +void +flush(void) +{ + DI; + fifo_clear(&rx_fifo); + EI; +} + + +// Hamming(7,4) encoding +uint8_t +encode(uint8_t x) +{ + uint8_t y = 0; + const uint8_t c[4] = {0x61, 0x52, 0x34, 0x78}; + + for (uint8_t i = 0; i < 4; ++i) + y ^= ((x >> i) & 1) ? c[i] : 0; + + return y; +} + +// Hamming(7,4) decoding +uint8_t +decode(uint8_t x) +{ + uint8_t p = 0; + const uint8_t r[7] = {6, 5, 3, 7, 1, 2, 4}; + + for (int i = 0; i < 7; ++i) + p ^= ((x >> i) & 1) ? r[i] : 0; + + // Assume simple error, attempt correction + if (p) { + size_t i = 0; + + for (i = 0; i < LEN(r); ++i) { + if (r[i] == x) + break; + } + + x ^= (1 << i); + } + + return x & 0x0F; +} + + +int +read(void *buf, size_t count) +{ + uint8_t b; + uint8_t *p = buf; + + for (int n = 0; n < count; ++n) { + b = decode(getbyte()); + if (errno) + return errno; + + b |= (decode(getbyte()) << 4); + if (errno) + return errno; + + p[n] = b; + } + + return 0; +} + +int +write(const void *buf, size_t count) +{ + const uint8_t *p = buf; + + for (size_t i = 0; i < count; ++i) { + putbyte(encode(p[i] & 0x0F)); + putbyte(encode((p[i] >> 4) & 0x0F)); + } + + return 0; +} + +int +read_header(struct header *header) +{ + int err; + uint8_t ack; + uint16_t checksum; + + while (1) { + if ((err = read(header, sizeof(*header)))) + return err; + + checksum = header->checksum; + header->checksum = 0; + + if (checksum == crc16(header, sizeof(*header))) { + header->checksum = checksum; + ack = ACK; + write(&ack, sizeof(ack)); + return 0; + } else { + ack = NACK; + write(&ack, sizeof(ack)); + } + } +} + +int +read_buf(size_t len, void *buf) +{ + int err; + uint8_t ack; + uint16_t checksum; + + for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i) { + // TODO: reduce code? + if ((err = read(&checksum, sizeof(checksum))) + || (err = read(buf, len))) + break; + + if (checksum == crc16(buf, len)) { + ack = ACK; + write(&ack, sizeof(ack)); + return 0; + } else { + ack = NACK; + write(&ack, sizeof(ack)); + } + } + + return -1; +} + +int +write_buf(size_t len, const void *buf) +{ + int err; + uint8_t ack = NACK; + uint16_t checksum = crc16(buf, len); + + for (int i = 0; i < MAX_TRANS_ATTEMPTS; ++i){ + write(&checksum, sizeof(checksum)); + write(buf, len); + + // If TIMEOUT sending just give up + if ((err = read(&ack, sizeof(ack)))) + return err; + + if (ack == ACK) + return 0; + } + + return -1; +} + +// TODO: Restart after timeouts +void +loop(void) +{ + struct header header; + uint8_t buf[MAX_PACKET_SIZE]; + + while (1) { + if (read_header(&header)) { + flush(); + continue; + } + + switch (header.type) { + case CMD_BOOT: + ((void (*)(void))header.address)(); + break; + + case CMD_READ: + write_buf(header.length, (const void *)header.address); + break; + + case CMD_WRITE: + if (!read_buf(header.length, buf)) + memcpy((void *)header.address, buf, header.length); + break; + + case CMD_ECHO: + if (!read_buf(header.length, buf)) + write_buf(header.length, buf); + break; + + default: + break; + } + + flush(); + } +} + +int +main(void) +{ + // Init CTC + // 16 prescaler, timer mode + ctc_channel_1 = (CTC_CLK_TRG_BIT | CTC_TIME_CONST_BIT | CTC_RST_BIT + | CTC_CTRL_OR_VECTOR_BIT); + ctc_channel_1 = (CPU_FREQ / 16 / 9600); + + // 200Hz clock + ctc_channel_3 = (CTC_INT_BIT | CTC_PRESCALER_BIT | CTC_CLK_TRG_BIT | + CTC_TIME_CONST_BIT | CTC_RST_BIT | CTC_CTRL_OR_VECTOR_BIT); + ctc_channel_3 = (CPU_FREQ / 256 / 36); + ctc_channel_0 = ISR_OFFSET(ctc3_isr_ptr) | (3 << 1); + + // Init SIO + for (uint8_t i = 0; i < LEN(sio_a_cfg); ++i) + sio_a_ctrl = sio_a_cfg[i]; + + for (uint8_t i = 0; i < LEN(sio_b_cfg); ++i) + sio_b_ctrl = sio_b_cfg[i]; + + // Interrupt mode 2 + IM(2); + // Enable interrupts + EI; + + loop(); + return 0; +} diff --git a/zbootloader.h b/zbootloader.h new file mode 100644 index 0000000..2d1aff6 --- /dev/null +++ b/zbootloader.h @@ -0,0 +1,58 @@ +#ifndef ZBOOTLOADER_H +#define ZBOOTLOADER_H + +#include +#include +#include +#include + +#ifdef __GNUC__ +#define PACKED __attribute__((packed)) +#else +#define PACKED +#endif + +enum header_type { + CMD_PING, + CMD_INFO, + CMD_BOOT, + CMD_READ, + CMD_WRITE, + CMD_IO_READ, + CMD_IO_WRITE, + CMD_ECHO +}; + +struct header { + uint8_t type; + uint8_t bank; + uint16_t address; + uint16_t length; + uint16_t checksum; +} PACKED; + +static_assert(sizeof(struct header) == 8, "struct header is not PACKED"); + +enum ack { + ACK = 0x00, + NACK = 0xFF +}; + +enum error { + ERR_TIMEOUT = -1 +}; + +#define LEN(x) ((size_t)(sizeof(x) / sizeof(x[0]))) + +#define FIFO_LEN 32 +#define MAX_PACKET_SIZE 256 +#define TIMEOUT_MS 500 +#define MAX_ATTEMPTS 3 +#define MAX_TRANS_ATTEMPTS 5 + +// static_assert(FIFO_LEN % 2 == 0, "FIFO_LEN is not a power of 2"); + +uint16_t +crc16(const void *buf, size_t len); + +#endif // ZBOOTLOADER_H diff --git a/zeta.h b/zeta.h new file mode 100644 index 0000000..b5f08f9 --- /dev/null +++ b/zeta.h @@ -0,0 +1,153 @@ +#ifndef ZETA_H +#define ZETA_H + +/* + * zeta hardware definitions + */ + +#define CPU_FREQ 1843200 // 1.8432 MHz + +#define EXT_CE_0 0x80 +#define EXT_CE_1 0x90 +#define EXT_CE_2 0xA0 +#define EXT_CE_3 0xB0 +#define EXT_CE_4 0xC0 +#define EXT_CE_5 0xD0 +#define EXT_CE_6 0xE0 +#define EXT_CE_7 0xF0 + +// ******************************************************** + +#define SREG_CTRL 0x00 +#define SREG_EXT_MEM 0x01 +#define SREG_MODEM_CTRL_A 0x02 +#define SREG_MODEM_CTRL_B 0x04 +#define SREG_MEM_LOCK 0x08 +#define SREG_DMA_RDY_EN 0x10 +#define SREG_DMA_RDY_0 0x20 +#define SREG_DMA_RDY_1 0x40 +#define SREG_DMA_RDY_2 0x80 + +// ******************************************************** + +#define WIN_0_CTRL 0x10 +#define WIN_1_CTRL 0x11 +#define WIN_2_CTRL 0x12 +#define WIN_3_CTRL 0x13 + +#define WIN_0_BASE 0x0000 +#define WIN_1_BASE 0x4000 +#define WIN_2_BASE 0x8000 +#define WIN_3_BASE 0xC000 + +#define ROM_FIRST_BANK 0b00000000 +#define ROM_LAST_BANK 0b00011111 +#define RAM_FIRST_BANK 0b00100000 +#define RAM_LAST_BANK 0b01111111 + +// ******************************************************** + +#define CTC_CHANNEL_0 0x20 +#define CTC_CHANNEL_1 0x21 +#define CTC_CHANNEL_2 0x22 +#define CTC_CHANNEL_3 0x23 + +#define CTC_CTRL_OR_VECTOR_BIT 0x01 +#define CTC_RST_BIT 0x02 +#define CTC_TIME_CONST_BIT 0x04 +#define CTC_TIME_TRG_BIT 0x08 +#define CTC_CLK_TRG_BIT 0x10 +#define CTC_PRESCALER_BIT 0x20 +#define CTC_MODE_BIT 0x40 +#define CTC_INT_BIT 0x80 + +// ******************************************************** + +#define SIO_A_DATA 0x30 +#define SIO_B_DATA 0x31 +#define SIO_A_CTRL 0x32 +#define SIO_B_CTRL 0x33 + +#define SIO_EX_INT_EN 0x01 +#define SIO_TX_INT_EN 0x02 +#define SIO_STATUS_AFFECTS_VECTOR 0x04 +#define SIO_RX_INT_MD0 0x08 +#define SIO_RX_INT_MD1 0x10 +#define SIO_WAIT_RDY_ON_RX_TX 0x20 +#define SIO_WAIT_RDY_FTN 0x40 +#define SIO_WAIT_RDY_EN 0x80 + +// ******************************************************** + +#define PORT_A_DATA 0x40 +#define PORT_B_DATA 0x41 +#define PORT_A_CTRL 0x42 +#define PORT_B_CTRL 0x43 + +#define PIO_MODE_0 0b00001111 +#define PIO_MODE_1 0b01001111 +#define PIO_MODE_2 0b10001111 +#define PIO_MODE_3 0b11001111 + +// ******************************************************** + +#define DMA_CTRL 0x50 + +#define DMA_RST 0xC3 +#define DMA_RST_PORT_A_TIMING 0xC7 +#define DMA_RST_PORT_B_TIMING 0xC8 +#define DMA_LOAD 0xCF +#define DMA_CONTINUE 0xD3 +#define DMA_DISABLE_INTERRUPTS 0xAF +#define DMA_ENABLE_INTERRUPTS 0xAB +#define DMA_RST_AND_DISABLE_INTERRUPTS 0xA3 +#define DMA_ENABLE_AFTER_RETI 0xB7 +#define DMA_READ_STATUS_BYTE 0xBF +#define DMA_REINITILIAZE_STATUS_BYTE 0x8B +#define DMA_INITIALIZE_READ_SEQUENCE 0xA7 +#define DMA_FORCE_READY 0xB3 +#define DMA_ENABLE 0x87 +#define DMA_DISABLE 0x83 +#define DMA_READ_MASK_FOLLOWS 0xBB + +// ******************************************************** + +#define RTC_SECONDS 0x60 +#define RTC_MINUTES 0x61 +#define RTC_HOURS 0x62 +#define RTC_DAY 0x63 +#define RTC_DATE 0x64 +#define RTC_MONTH 0x65 +#define RTC_YEAR 0x66 +#define RTC_CENTURY 0x67 +#define RTC_ALARM_SECONDS 0x68 +#define RTC_ALARM_MINUTES 0x69 +#define RTC_ALARM_HOURS 0x6A +#define RTC_ALARM_DAY_DATE 0x6B +#define RTC_WATCHDOG_A 0x6C +#define RTC_WATCHDOG_B 0x6D +#define RTC_CONTROL_A 0x6E +#define RTC_CONTROL_B 0x6F +#define RTC_RAM_ADDRESS 0x70 +#define RTC_RAM_DATA 0x73 + +// +#ifndef ASSEMBLY + +__sfr __at CTC_CHANNEL_0 ctc_channel_0; +__sfr __at CTC_CHANNEL_1 ctc_channel_1; +__sfr __at CTC_CHANNEL_2 ctc_channel_2; +__sfr __at CTC_CHANNEL_3 ctc_channel_3; + +__sfr __at SIO_A_DATA sio_a_data; +__sfr __at SIO_B_DATA sio_b_data; +__sfr __at SIO_A_CTRL sio_a_ctrl; +__sfr __at SIO_B_CTRL sio_b_ctrl; + +#define IM(__mode) __asm__("im " #__mode) +#define EI __asm__("ei") +#define DI __asm__("di") + +#endif // ASSEMBLY + +#endif /* ZETA_H */ -- cgit v1.2.3