Initial commit
This commit is contained in:
@@ -0,0 +1 @@
|
||||
build
|
||||
@@ -0,0 +1,56 @@
|
||||
TARGET := monitor
|
||||
BUILDDIR := build
|
||||
|
||||
METAL_C_SRCFILES := $(wildcard *.c)
|
||||
METAL_ASM_SRCFILES := $(wildcard *.asm)
|
||||
METAL_RELFILES := $(METAL_ASM_SRCFILES:%.asm=$(BUILDDIR)/metal/%.rel) \
|
||||
$(METAL_C_SRCFILES:%.c=$(BUILDDIR)/metal/%.rel)
|
||||
|
||||
MUSIC_FILE := updraft_flight
|
||||
|
||||
METAL_CC := sdcc
|
||||
METAL_AS := sdasz80
|
||||
METAL_MAKEBIN := makebin
|
||||
METAL_FLAGS := -mz80 --no-std-crt0 --code-loc 0x0080 --data-loc 0x8000
|
||||
METAL_CPPFLAGS := -I src -I $(BUILDDIR)/metal/generated --disable-warning 283
|
||||
METAL_BIN_SIZE := 32768
|
||||
METAL_RAM_SIZE := 32768
|
||||
|
||||
.DEFAULT_GOAL := metal
|
||||
|
||||
.PHONY: all metal clean
|
||||
|
||||
all: metal
|
||||
|
||||
metal: $(BUILDDIR)/metal/$(TARGET).ihx $(BUILDDIR)/metal/$(TARGET).bin $(BUILDDIR)/metal/$(TARGET).prog.bin
|
||||
@awk -v rom_capacity=$(METAL_BIN_SIZE) -v ram_capacity=$(METAL_RAM_SIZE) '\
|
||||
$$1 ~ /^_(CODE|HOME|GSINIT|GSFINAL|INITIALIZER|ITABLE[0-7]*)$$/ { rom += $$5 } \
|
||||
$$1 ~ /^_(DATA|INITIALIZED|BSEG|BSS|HEAP|STACK)$$/ { ram += $$5 } \
|
||||
END { \
|
||||
printf "\nMemory usage:\n"; \
|
||||
printf " ROM: %5u / %5u bytes (%5.1f%%), %5u bytes free\n", rom, rom_capacity, 100 * rom / rom_capacity, rom_capacity - rom; \
|
||||
printf " RAM: %5u / %5u bytes (%5.1f%%), %5u bytes free\n", ram, ram_capacity, 100 * ram / ram_capacity, ram_capacity - ram; \
|
||||
}' $(BUILDDIR)/metal/$(TARGET).map
|
||||
|
||||
$(BUILDDIR)/metal/$(TARGET).ihx: $(METAL_RELFILES)
|
||||
@mkdir -p $(@D)
|
||||
$(METAL_CC) $(METAL_FLAGS) -o $@ $(METAL_RELFILES)
|
||||
|
||||
$(BUILDDIR)/metal/$(TARGET).bin: $(BUILDDIR)/metal/$(TARGET).ihx
|
||||
$(METAL_MAKEBIN) -s $(METAL_BIN_SIZE) $< $@
|
||||
|
||||
$(BUILDDIR)/metal/$(TARGET).prog.bin: $(BUILDDIR)/metal/$(TARGET).ihx
|
||||
$(METAL_MAKEBIN) -p $< $@
|
||||
|
||||
$(BUILDDIR)/metal/%.rel: %.c
|
||||
@mkdir -p $(@D)
|
||||
$(METAL_CC) $(METAL_FLAGS) $(METAL_CPPFLAGS) -o $@ -c $<
|
||||
|
||||
$(BUILDDIR)/metal/%.rel: %.asm
|
||||
@mkdir -p $(@D)
|
||||
$(METAL_AS) -plosgff -o $@ $<
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILDDIR)
|
||||
|
||||
-include $(EMU_DEPFILES)
|
||||
@@ -0,0 +1,175 @@
|
||||
STACK_TOP = 0xFFFF
|
||||
DELAY_LOOPS_PER_MS = 40
|
||||
|
||||
.globl _main
|
||||
.globl _delay_ms
|
||||
.globl _io_out
|
||||
.globl _io_in
|
||||
.globl _enable_interrupts
|
||||
.globl _disable_interrupts
|
||||
.globl s__DATA
|
||||
.globl l__DATA
|
||||
.globl s__INITIALIZER
|
||||
.globl s__INITIALIZED
|
||||
.globl l__INITIALIZER
|
||||
|
||||
.area _ITABLE (ABS)
|
||||
|
||||
.org 0x00
|
||||
jp init
|
||||
.org 0x08
|
||||
reti
|
||||
.org 0x10
|
||||
reti
|
||||
.org 0x18
|
||||
reti
|
||||
.org 0x20
|
||||
reti
|
||||
.org 0x28
|
||||
reti
|
||||
.org 0x30
|
||||
reti
|
||||
.org 0x38
|
||||
reti
|
||||
|
||||
; ITABLE
|
||||
.org 0x40
|
||||
.dw ctc_isr ; CTC channel 0: vector 0x40
|
||||
.dw ctc_isr ; CTC channel 1: vector 0x42
|
||||
.dw ctc_isr ; CTC channel 2: vector 0x44
|
||||
.dw uart_isr ; CTC channel 3: vector 0x46
|
||||
|
||||
.area _HOME
|
||||
init:
|
||||
di
|
||||
ld sp, #STACK_TOP
|
||||
|
||||
call gsinit
|
||||
|
||||
; Setup interrupt mode 2
|
||||
xor a
|
||||
ld i, a
|
||||
im 2
|
||||
call _main
|
||||
|
||||
hang:
|
||||
jr hang
|
||||
|
||||
.area _GSINIT
|
||||
gsinit:
|
||||
ld bc, #l__INITIALIZER
|
||||
ld a, b
|
||||
or c
|
||||
jr z, zero_data
|
||||
|
||||
ld de, #s__INITIALIZED
|
||||
ld hl, #s__INITIALIZER
|
||||
ldir
|
||||
|
||||
zero_data:
|
||||
ld bc, #l__DATA
|
||||
ld a, b
|
||||
or c
|
||||
jr z, gsinit_done
|
||||
|
||||
ld hl, #s__DATA
|
||||
xor a
|
||||
|
||||
clear_loop:
|
||||
xor a ; BC loop test below changes A
|
||||
ld (hl), a
|
||||
inc hl
|
||||
dec bc
|
||||
ld a, b
|
||||
or c
|
||||
jr nz, clear_loop
|
||||
|
||||
gsinit_done:
|
||||
.area _GSFINAL
|
||||
ret
|
||||
|
||||
.area _CODE
|
||||
|
||||
.macro MAKE_ISR entry, handler
|
||||
.globl handler
|
||||
entry:
|
||||
push af
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
push ix
|
||||
push iy
|
||||
|
||||
ex af, af'
|
||||
push af
|
||||
exx
|
||||
push bc
|
||||
push de
|
||||
push hl
|
||||
|
||||
call handler
|
||||
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
exx
|
||||
pop af
|
||||
ex af, af'
|
||||
|
||||
pop iy
|
||||
pop ix
|
||||
pop hl
|
||||
pop de
|
||||
pop bc
|
||||
pop af
|
||||
ei
|
||||
reti
|
||||
.endm
|
||||
|
||||
MAKE_ISR ctc_isr, _ctc_interrupt
|
||||
MAKE_ISR uart_isr, _uart_interrupt
|
||||
|
||||
_enable_interrupts::
|
||||
ei
|
||||
ret
|
||||
|
||||
_disable_interrupts::
|
||||
di
|
||||
ret
|
||||
|
||||
; Write a byte to an I/O port.
|
||||
; Input: A = port address, L = data byte.
|
||||
_io_out::
|
||||
ld c, a
|
||||
ld a, l
|
||||
out (c), a
|
||||
ret
|
||||
|
||||
; Read a byte from an I/O port.
|
||||
; Input: A = port address.
|
||||
; Return: A = data byte.
|
||||
_io_in::
|
||||
ld c, a
|
||||
in a, (c)
|
||||
ret
|
||||
|
||||
; Approximate millisecond delay.
|
||||
; Input: HL = delay in milliseconds.
|
||||
_delay_ms::
|
||||
ld a, h
|
||||
or l
|
||||
ret z
|
||||
delay_ms_outer$:
|
||||
push hl
|
||||
ld hl, #DELAY_LOOPS_PER_MS
|
||||
delay_ms_inner$:
|
||||
dec hl
|
||||
ld a, h
|
||||
or l
|
||||
jr nz, delay_ms_inner$
|
||||
pop hl
|
||||
dec hl
|
||||
ld a, h
|
||||
or l
|
||||
jr nz, delay_ms_outer$
|
||||
ret
|
||||
@@ -0,0 +1,10 @@
|
||||
#ifndef __H_BOOT
|
||||
#include <stdint.h>
|
||||
|
||||
void io_out(uint8_t a, uint8_t d);
|
||||
uint8_t io_in(uint8_t d);
|
||||
void delay_ms(uint16_t t);
|
||||
void enable_interrupts();
|
||||
void disable_interrupts();
|
||||
|
||||
#endif
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
#include "circ_buf.h"
|
||||
|
||||
void buffer_init(volatile circular_buffer_t* b){
|
||||
b->count = 0;
|
||||
b->head = 0;
|
||||
b->tail = 0;
|
||||
}
|
||||
|
||||
uint8_t buffer_is_full(volatile circular_buffer_t* b){
|
||||
return b->count == BUFFER_SIZE;
|
||||
}
|
||||
|
||||
uint8_t buffer_is_empty(volatile circular_buffer_t* b){
|
||||
return b->count == 0;
|
||||
}
|
||||
|
||||
uint8_t buffer_enqueue(volatile circular_buffer_t* b, char c){
|
||||
if(buffer_is_full(b))
|
||||
return 0;
|
||||
b->data[b->head] = c;
|
||||
b->head = (b->head+1)%BUFFER_SIZE;
|
||||
b->count++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint8_t buffer_dequeue(volatile circular_buffer_t* b, char* c){
|
||||
if(buffer_is_empty(b))
|
||||
return 0;
|
||||
*c = b->data[b->tail];
|
||||
b->tail = (b->tail+1)%BUFFER_SIZE;
|
||||
b->count--;
|
||||
return 1;
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
#ifndef __H_CIRC_BUF
|
||||
#include <stdint.h>
|
||||
|
||||
#define BUFFER_SIZE 5
|
||||
|
||||
typedef struct {
|
||||
char data[BUFFER_SIZE];
|
||||
uint8_t head;
|
||||
uint8_t tail;
|
||||
uint8_t count;
|
||||
} circular_buffer_t;
|
||||
|
||||
void buffer_init(volatile circular_buffer_t* b);
|
||||
uint8_t buffer_is_full(volatile circular_buffer_t* b);
|
||||
uint8_t buffer_is_empty(volatile circular_buffer_t* b);
|
||||
uint8_t buffer_enqueue(volatile circular_buffer_t* b, char c);
|
||||
uint8_t buffer_dequeue(volatile circular_buffer_t* b, char* c);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,109 @@
|
||||
#include <stdint.h>
|
||||
#include "boot.h"
|
||||
#include "circ_buf.h"
|
||||
|
||||
#define CPUREG 0x00
|
||||
#define CPUREG_ROM_DISABLE 0x01
|
||||
#define CPUREG_BANK_SELECT 0x02
|
||||
#define CPUREG_BANK_ENABLE 0x04
|
||||
#define CPUREG_GPO_0 0x08
|
||||
#define CPUREG_GPO_1 0x10
|
||||
#define CPUREG_GPO_2 0x20
|
||||
#define CPUREG_GPO_3 0x40
|
||||
#define CPUREG_GPO_4 0x80
|
||||
#define CPUREG_GPO_MASK 0xf8
|
||||
|
||||
#define UART_CTC_CARD_BASE 0x20
|
||||
|
||||
#define CTC_BASE (UART_CTC_CARD_BASE+0x00)
|
||||
#define CTC_CHANNEL_0 (CTC_BASE+0)
|
||||
#define CTC_CHANNEL_1 (CTC_BASE+1)
|
||||
#define CTC_CHANNEL_2 (CTC_BASE+2)
|
||||
#define CTC_CHANNEL_3 (CTC_BASE+3)
|
||||
|
||||
#define UART_BASE (UART_CTC_CARD_BASE+0x04)
|
||||
#define UART_CONTROL (UART_BASE+0)
|
||||
#define UART_DATA (UART_BASE+1)
|
||||
|
||||
volatile uint8_t v;
|
||||
volatile uint8_t uart_tx_busy;
|
||||
volatile circular_buffer_t rx_buf;
|
||||
volatile circular_buffer_t tx_buf;
|
||||
|
||||
void uart_puts(char * c){
|
||||
while(*c){
|
||||
// fill tx buffer till it is full
|
||||
while(*c && buffer_enqueue(&tx_buf, *c)){
|
||||
c++;
|
||||
}
|
||||
// if uart not busy kick off
|
||||
if(!uart_tx_busy){
|
||||
disable_interrupts();
|
||||
char cc;
|
||||
if(buffer_dequeue(&tx_buf, &cc)){
|
||||
uart_tx_busy = 1;
|
||||
io_out(UART_DATA, cc);
|
||||
io_out(UART_CONTROL, 0b10110101);
|
||||
}
|
||||
enable_interrupts();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void uart_interrupt(){
|
||||
uint8_t status = io_in(UART_CONTROL);
|
||||
|
||||
if((status&0x21)!=0){
|
||||
// RDRF or OVRN
|
||||
char c = io_in(UART_DATA);
|
||||
if((status&0x01)!=0){
|
||||
// RDRF
|
||||
buffer_enqueue(&rx_buf, c);
|
||||
}
|
||||
}
|
||||
|
||||
if((status&0x02)!=0 && uart_tx_busy){
|
||||
//TXRE
|
||||
char c;
|
||||
if(buffer_dequeue(&tx_buf, &c)){
|
||||
io_out(UART_DATA, c);
|
||||
}else{
|
||||
io_out(UART_CONTROL, 0b10010101);
|
||||
uart_tx_busy = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ctc_interrupt(){
|
||||
}
|
||||
|
||||
void main(){
|
||||
buffer_init(&rx_buf);
|
||||
buffer_init(&tx_buf);
|
||||
|
||||
io_out(CTC_CHANNEL_0, 0x57); // no int, counter @ rising, value follows, soft reset, control word
|
||||
io_out(CTC_CHANNEL_0, 13); // 38.462 kHz out;
|
||||
|
||||
io_out(CTC_CHANNEL_3, 0b11001111); // int, counter @ falling, ext trig, value follows, soft reset, control word
|
||||
io_out(CTC_CHANNEL_3, 1);
|
||||
|
||||
io_out(CTC_CHANNEL_0, 0x00); // vector follows
|
||||
io_out(CTC_CHANNEL_0, 0x40);
|
||||
|
||||
uart_tx_busy = 0;
|
||||
io_out(UART_CONTROL, 0b00000011); // master reset
|
||||
io_out(UART_CONTROL, 0b10010101); // recv int, 8N1, /16 -> 2403.85 baud
|
||||
|
||||
enable_interrupts();
|
||||
|
||||
uart_puts("Z80 monitor - v1\r\n");
|
||||
uart_puts("----------------\r\n");
|
||||
|
||||
v = 0;
|
||||
for(;;){
|
||||
char c[2] = {0, 0};
|
||||
while(buffer_dequeue(&rx_buf, c)){
|
||||
uart_puts(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user