eris2010

Documentation: http://frombelow.net/projects/eris2010/
Clone: git clone https://git.frombelow.net/eris2010.git
Log | Files | Refs | Submodules | README | LICENSE

commit a33ba6bc619440ee0f9b704d519255cabdc5dda3
parent 3fceb94389d2d61507b1aeadb13b5a7763772f3f
Author: Gerd Beuster <gerd@frombelow.net>
Date:   Sun, 15 Nov 2020 22:17:41 +0100

Updates, bug fixes, interrupt support

Diffstat:
M.gitignore | 5+++++
Mhw/bus_logic/BUS_LOGIC.PLD | 27+++++++++++----------------
Mmisc/clock_reset_attiny45/clock_and_reset.c | 31+++++++++++++++++++++++++------
Mroms/boot/boot.py | 9+++++++++
Mroms/boot/boot.s | 82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------
Msw/10print/10print.s | 10++++++++++
Msw/SW.txt | 20++++++++++++++++++--
Asw/aaa/Makefile | 16++++++++++++++++
Asw/aaa/aaa.s | 44++++++++++++++++++++++++++++++++++++++++++++
Asw/interrupts/Makefile | 16++++++++++++++++
Asw/interrupts/interrupts.s | 77+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
11 files changed, 300 insertions(+), 37 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -7,6 +7,11 @@ hw/bus_logic/BUS_LOGIC.jed hw/bus_logic/BUS_LOGIC.pdf hw/bus_logic/BUS_LOGIC.si hw/bus_logic/BUS_LOGIC.sim +hw/bus_logic/BUS_LOGIC.lst +hw/bus_logic/BUS_LOGIC.mx +hw/bus_logic/BUS_LOGIC.pla +hw/bus_logic/BUS_LOGIC.so +hw/bus_logic/BUS_LOGIC.wo misc/clock_reset_attiny45/clock_and_reset.bin misc/clock_reset_attiny45/clock_and_reset.elf misc/clock_reset_attiny45/clock_and_reset.hex diff --git a/hw/bus_logic/BUS_LOGIC.PLD b/hw/bus_logic/BUS_LOGIC.PLD @@ -21,9 +21,9 @@ pin 7 = i5; /* cpu_A10 */ pin 8 = reset_in; /* Reset logic output */ pin 9 = phi; /* cpu_PHI2 */ pin 12 = o0; /* eeprom_#ce */ -pin 13 = o1; /* #oe */ +pin 13 = o1; /* ram_#oe */ pin 14 = o2; /* acai_#cs0 */ -pin 15 = o3; /* ce (not assigned) */ +pin 15 = o3; /* ram_#ce */ pin 16 = o4; /* ce (not assigned) */ pin 17 = o5; /* ce (not assigned) */ pin 18 = o6; /* #we */ @@ -41,7 +41,7 @@ o0 = (!i0 # !i1 # !i2); Bit pattern: 0b0............... */ -/* Connect a14 directly to ram_#ce */ +/* See below */ /* ACIA (1k) Address range: 0xdc00 - 0xdfff @@ -55,22 +55,14 @@ o2 = (!i0 # !i1 # i2 # !i3 # !i4 # !i5); Bit pattern: 0b110110.......... */ -o3 = (!i0 # !i1 # i2 # !i3 # !i4 # i5); +o4 = (!i0 # !i1 # i2 # !i3 # !i4 # i5); /* TBA (1k) Address range: 0xd400 - 0xd7ff Bit pattern: 0b110101.......... */ -o4 = (!i0 # !i1 # i2 # !i3 # i4 # !i5); - -/* TBA (1k) - Address range: 0xd000 - 0xd3ff - Bit pattern: 0b110100.......... -*/ - -o5 = (!i0 # !i1 # i2 # !i3 # i4 # i5); - +o5 = (!i0 # !i1 # i2 # !i3 # i4 # !i5); /* Inverter This is not part of the bus logic. @@ -81,14 +73,17 @@ o5 = (!i0 # !i1 # i2 # !i3 # i4 # i5); o7 = !reset_in; /* -oe# and we# for the memory chips must be +oe# we#, and ce# for the memory chips must be qualified by phi - No memory access in the first part of the cycle, while phi is low. */ -/* oe# */ +/* ram_oe# */ o1 = !phi # !rwb; -/* we# */ +/* ram_ce# */ +o3 = !phi # i0; + +/* ram_we# */ o6 = !phi # rwb; diff --git a/misc/clock_reset_attiny45/clock_and_reset.c b/misc/clock_reset_attiny45/clock_and_reset.c @@ -5,20 +5,34 @@ // Set rest pin low for this number of iterations if reset is triggered. #define RESET_DELAY 0x4F -int main (void){ - /* usb_init(); */ - SET_MODE_OUTPUT_DIGITAL(CONTACT_2_DDR_REG, - CONTACT_2_DDR_BIT); - SET_MODE_OUTPUT_DIGITAL(CONTACT_3_DDR_REG, - CONTACT_3_DDR_BIT); + +void fast_clock (void){ SET_MODE_OUTPUT_DIGITAL(CONTACT_5_DDR_REG, CONTACT_5_DDR_BIT); + while(1) { + CONTACT_5_PORT_REG ^= 0xFF; + // No delay: 842.1 kHz + // _delay_us(3); // 516,1 kHz + _delay_us(37); // 99,38 kHz + } +} + +void clock_and_reset (void){ + /* usb_init(); */ + /* Configure Pins for reset logic. */ SET_MODE_INPUT_PULLUP(CONTACT_6_DDR_REG, CONTACT_6_DDR_BIT, CONTACT_6_PORT_REG, CONTACT_6_PORT_BIT); SET_MODE_OUTPUT_DIGITAL(CONTACT_7_DDR_REG, CONTACT_7_DDR_BIT); + /* Configure pins for clock signal. */ + SET_MODE_OUTPUT_DIGITAL(CONTACT_2_DDR_REG, + CONTACT_2_DDR_BIT); + SET_MODE_OUTPUT_DIGITAL(CONTACT_3_DDR_REG, + CONTACT_3_DDR_BIT); + SET_MODE_OUTPUT_DIGITAL(CONTACT_5_DDR_REG, + CONTACT_5_DDR_BIT); uint8_t clock_counter = 0; uint16_t reset_counter = RESET_DELAY; // power on reset while (1){ @@ -48,5 +62,10 @@ int main (void){ } _delay_ms(20); } +} + +int main (void){ + fast_clock(); // Can't get fast PWM working. Using this instead... + // clock_and_reset(); return 1; // dummy } diff --git a/roms/boot/boot.py b/roms/boot/boot.py @@ -11,6 +11,10 @@ import os SERIAL_PORT = '/dev/ttyUSB0' SERIAL_SPEED = 19200 +# File upload does not work if GATE is run 100 kHz clock frequency +# unless SLOW_CPU is set. +SLOW_CPU = False +# SLOW_CPU = True def upload_program(filename): with open(filename, 'rb') as f: @@ -31,6 +35,7 @@ def upload_program(filename): print("Uploading program.") e = str.encode(chr(blocks)) s.write(e) + # While transferring data, we calculate a two byte # checksum. The first byte is the addition of all bytes @@ -40,6 +45,10 @@ def upload_program(filename): checksum_xor = 0 for d in data: print(".", end="", flush=True) + if SLOW_CPU: + # At slow clock frequencies, the upload has to + # to be slowed down. + time.sleep(.01) s.write(bytes([d])) # Update checksums checksum_add = (checksum_add + d) % 256 diff --git a/roms/boot/boot.s b/roms/boot/boot.s @@ -1,6 +1,8 @@ -;;; Receive data from termina. Store it in RAM & execute it. +;;; Receive data from terminal. Store it in RAM & execute it. #include "boot.h" + +#define CLOCK_4_MHZ #ifdef SYMON * = $c000 @@ -8,6 +10,13 @@ * = $e000 #endif +;;; The actual (hardware) interrupt vectors are located in the ROM +;;; at $ fffa/fffb (nmi) and $fffe/$ffff (irq). Since we want to be +;;; able to handle interrupts in RAM, the ROM isr routines jump to the +;;; addresses given here. After a reset, this RAM address is set to +;;; default_irq_handler. +nmi_vector = $7ffc ; EXPORT +irq_vector = $7ffe ; EXPORT ;;; We have enough space left to ;;; fit in a Tic-Tac-Toe engine! @@ -21,7 +30,11 @@ ;;; ---------------------------------------------------------- init: - cld + sei + STORE_WORD(default_irq_handler, irq_vector) + STORE_WORD(default_nmi_handler, nmi_vector) + cld + cli jsr init_acia jsr check_for_program_download bcs no_program_download @@ -141,22 +154,44 @@ puts: ; EXPORT _puts_loop: lda (puts_str), y beq _puts_end + phy jsr putc + ply iny jmp _puts_loop _puts_end: rts -putc: ; EXPORT - ;; Send character +#ifdef CLOCK_4_MHZ + SERIAL_SEND_DELAY_X = $c3 + SERIAL_SEND_DELAY_Y = $02 +#endif +#ifdef CLOCK_2_MHZ + SERIAL_SEND_DELAY_X = $c2 + SERIAL_SEND_DELAY_Y = $01 +#endif +#ifdef CLOCK_1_MHZ + SERIAL_SEND_DELAY_X = $88 + SERIAL_SEND_DELAY_Y = $01 +#endif +putc: ; EXPORT + .( + ;; Send character. + ;; Due to bugs in the register and interrupt + ;; handling of the WDC 65C02, we have to use + ;; a manual delay. sta acia_data_reg - ;; Length of delay loop determined experimentally - ldx #$88 -_putc_loop: - dex - bne _putc_loop - rts - + ldy #SERIAL_SEND_DELAY_Y +outer_loop: + ldx #SERIAL_SEND_DELAY_X +inner_loop: + dex + bne inner_loop + dey + bne outer_loop + rts + .) + puth: ; EXPORT ;; Send byte a as hex number pha @@ -286,6 +321,27 @@ loop: .) #endif // TESTS + +;;; Default IRQ handler. Unless the user program changes +;;; the irq_vector, IRQs are handled here. +default_irq_handler: + rti + +derefer_ram_irq: + ;; Jump to the address given in the IRQ vector + ;; in RAM + jmp (irq_vector) + +;;; Default NMI handler. Unless the user program changes +;;; the nmi_vector, NMIs are handled here. +default_nmi_handler: + rti + +derefer_ram_nmi: + ;; Jump to the address given in the NMI vector + ;; in RAM + jmp (nmi_vector) + ;;; Include Tic-Tac-Toe binary ;;; This creates some circular dependencies, ;;; because ttt.s includes liba.h, which @@ -300,6 +356,6 @@ loop: ;;; Vectors .dsb $fffa-*, $ff - .word $0000 ; nmi + .word derefer_ram_nmi ; nmi .word init ; reset - .word $0000 ; irq + .word derefer_ram_irq ; irq diff --git a/sw/10print/10print.s b/sw/10print/10print.s @@ -20,11 +20,21 @@ l0: jsr lfsr_step and #$01 bne slash +#ifdef SYMON + lda #'\' + jsr putc +#else PRINTS('╲') +#endif jsr putc jmp ten_print slash: +#ifdef SYMON + lda #'/' + jsr putc +#else PRINTS('╱') +#endif jsr putc jmp ten_print .) diff --git a/sw/SW.txt b/sw/SW.txt @@ -1,8 +1,24 @@ -mem_test/ +* mem_test/ Tests RAM write and read operations. Used to test if the CPU interacts with the RAM. -serial_line_echo/ +* serial_line_echo/ Test serial input/output. + +* 10print/ + +https://10print.org/ + +* aaa/ + +Output stream of 'a'. Used to calliberate serial interface. + +* interrupts + +Testing interrupt handling. + +* ttt/ + +Tic-Tac-Toe diff --git a/sw/aaa/Makefile b/sw/aaa/Makefile @@ -0,0 +1,16 @@ +TARGET=aaa.bin +TARGET_BASENAME=$(basename $(TARGET)) + +all: $(TARGET) $(TARGET_BASENAME)_symon.bin + +%.bin: %.s + xa -l "$(basename $@).l" -r -o "$@" "$<" + +%_symon.bin: %.s + xa -DSYMON -l "$(basename $@).l" -r -o "$@" "$<" + +upload: $(TARGET) + ../../roms/boot/boot.py $(TARGET) + +clean: + rm -f *.bin *.l diff --git a/sw/aaa/aaa.s b/sw/aaa/aaa.s @@ -0,0 +1,44 @@ +#include "../../roms/boot/liba.h" + + * = $0300 +init: + jsr init_acia + .( +loop: + lda #'A' + jsr my_putc + jmp loop + .) + +#define CLOCK_4_MHZ + +#ifdef CLOCK_4_MHZ + SERIAL_SEND_DELAY_X = $c3 + SERIAL_SEND_DELAY_Y = $02 +#endif +#ifdef CLOCK_2_MHZ + SERIAL_SEND_DELAY_X = $c2 + SERIAL_SEND_DELAY_Y = $01 +#endif +#ifdef CLOCK_1_MHZ + SERIAL_SEND_DELAY_X = $88 + SERIAL_SEND_DELAY_Y = $01 +#endif +my_putc: ; EXPORT + .( + ;; Send character. + ;; Due to bugs in the register and interrupt + ;; handling of the WDC 65C02, we have to use + ;; a manual delay. + sta acia_data_reg + ldy #SERIAL_SEND_DELAY_Y +outer_loop: + ldx #SERIAL_SEND_DELAY_X +inner_loop: + dex + bne inner_loop + dey + bne outer_loop + rts + .) + diff --git a/sw/interrupts/Makefile b/sw/interrupts/Makefile @@ -0,0 +1,16 @@ +TARGET=interrupts.bin +TARGET_BASENAME=$(basename $(TARGET)) + +all: $(TARGET) $(TARGET_BASENAME)_symon.bin + +%.bin: %.s + xa -l "$(basename $@).l" -r -o "$@" "$<" + +%_symon.bin: %.s + xa -DSYMON -l "$(basename $@).l" -r -o "$@" "$<" + +upload: $(TARGET) + ../../roms/boot/boot.py $(TARGET) + +clean: + rm -f *.bin *.l diff --git a/sw/interrupts/interrupts.s b/sw/interrupts/interrupts.s @@ -0,0 +1,77 @@ +#include "../../roms/boot/liba.h" + + * = $0300 + + flag = $30 + tmp = $31 + +init: + // jmp transmitter_interrupt + jmp receiver_interrupt + +;;; Looks like interrupt controlled tranmission is buggy. +;;; The only way to transmit seems to be a delay loop. +transmitter_interrupt: + .( + jsr init_acia + STORE_WORD(isr, irq_vector) + PRINTSNL('Push key to start.') + jsr getc +loop: + ;; Transmitter interrupt on + lda #%11000111 + sta acia_cmd_reg + ;; Send a byte + lda flag + jsr putc_irq + ;; Transmitter interrupt off + lda #%11001011 + sta acia_cmd_reg + jsr wait + jmp loop + +wait: + ldx #$7f +wait_loop: + dex + bne wait_loop + rts + .) + +receiver_interrupt: + .( + jsr init_acia + STORE_WORD(isr, irq_vector) + ;; Receiver interrupt on + lda acia_cmd_reg + lda #%11001001 + sta acia_cmd_reg + PRINTSNL("Start typing ...") +loop: + jsr getc + lda flag + jsr puth + PRINTNL + jmp loop + .) + +isr: + lda flag + inc + sta flag + ldx #$00 ; Indicate end of transmission + lda acia_status_reg + rti + + +putc_irq: + .( + ldx #$ff + sta acia_data_reg +wait_for_transmission_finish: + ;; Interrupt upon successful transmission + ;; sets X to $00 + cpx #$00 + bne wait_for_transmission_finish + rts + .)