eris2010

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

commit 255bb36f28a68e2e07a532b2c660f0ec72c58d53
parent 823b04b8d5102252002d6fb25c544c8dd7deb785
Author: Gerd Beuster <gerd@frombelow.net>
Date:   Mon, 31 Aug 2020 09:27:16 +0200

The computer works!

Diffstat:
M.gitignore | 22++++++++++++++++++++--
D6502_monitor/machine.py | 22----------------------
D6502_monitor/monitor.py | 228-------------------------------------------------------------------------------
AREADME.txt | 1+
Adoc/Documentation.txt | 82+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adoc/notizen.txt | 67+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ahw/bus_logic/BUS_LOGIC.PLD | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/6502_monitor/Makefile | 7+++++++
Amisc/6502_monitor/machine.py | 22++++++++++++++++++++++
Amisc/6502_monitor/monitor.py | 266+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/clock_reset_attiny45/Makefile | 35+++++++++++++++++++++++++++++++++++
Amisc/clock_reset_attiny45/clock_and_reset.c | 52++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/sd_card/card_info.csv | 312+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Amisc/sd_card/esp32_sdcard.py | 14++++++++++++++
Dnotizen.txt | 152-------------------------------------------------------------------------------
Aroms/ROMS.txt | 25+++++++++++++++++++++++++
Aroms/boot/Makefile | 19+++++++++++++++++++
Aroms/boot/boot.py | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/boot/boot.s | 279+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/nop/nop.bin | 2++
Aroms/serial_char_out/Makefile | 10++++++++++
Aroms/serial_char_out/count_receive_errors.py | 25+++++++++++++++++++++++++
Aroms/serial_char_out/serial_char_out.s | 51+++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/serial_echo/Makefile | 15+++++++++++++++
Aroms/serial_echo/serial_echo.s | 103+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aroms/simple_loop/Makefile | 10++++++++++
Aroms/simple_loop/loop.s | 16++++++++++++++++
Dskizze.kra | 0
Asw/SW.txt | 4++++
Asw/mem_test/Makefile | 15+++++++++++++++
Asw/mem_test/liba.h | 123+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asw/mem_test/liba.s | 60++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asw/mem_test/mem_test.s | 59+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
33 files changed, 1856 insertions(+), 404 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,21 @@ -datasheets/ -6502_monitor/__pycache__/ +doc/datasheets/ +misc/6502_monitor/__pycache__/ *~ +hw/bus_logic/BUS_LOGIC.abs +hw/bus_logic/BUS_LOGIC.doc +hw/bus_logic/BUS_LOGIC.jed +hw/bus_logic/BUS_LOGIC.pdf +hw/bus_logic/BUS_LOGIC.si +hw/bus_logic/BUS_LOGIC.sim +misc/clock_reset_attiny45/clock_and_reset.bin +misc/clock_reset_attiny45/clock_and_reset.elf +misc/clock_reset_attiny45/clock_and_reset.hex +misc/clock_reset_attiny45/clock_and_reset.map +roms/serial_char_out/serial_char_out +roms/serial_echo/serial_echo +roms/serial_echo/serial_echo_symon +roms/simple_loop/loop +sw/mem_test/mem_test +sw/mem_test/mem_test.l +sw/mem_test/mem_test_symon +sw/mem_test/mem_test_symon.l diff --git a/6502_monitor/machine.py b/6502_monitor/machine.py @@ -1,22 +0,0 @@ -# Dummy class to run ESP32 programs on normal PC - -import random - -class Pin(): - - OUT = 0 - IN = 1 - PULL_UP = 2 - - def __init__(self, _direction, _pullup): - pass - - def on(self): - pass - - def off(self): - pass - - def value(self): - return random.choice([0, 1]) - diff --git a/6502_monitor/monitor.py b/6502_monitor/monitor.py @@ -1,228 +0,0 @@ -#!/usr/bin/env python3 -"""Monitor and control 6502 busses - -This program controls the busses (and other required signals like PHI2) -of a 6502 from an ESP32.""" - -import sys -import machine -import time -import pdb - -# Connect 6502 address bus (mostly) to left side of ESP32 -# Can I really use GPIO10? -# A14 & A15 not connect due to lack of GPIO pins -A_Pins = [36, 39, 34, 35, 32, 33, 25, 26, 27, 14, 12, 13, 10, 15] -D_Pins = [2, 0, 4, 16, 17, 5, 18, 19] -RW_Pin = 21 -PHI2_Pin = 22 -RST_Pin = 23 - -# Max memory size is 2**14, because due to a lack of GPIO pins, only -# A0..A13 are connected -MEM_SIZE = 2**14 -mem = bytearray(MEM_SIZE) -# By default, we emulate memory. This allows to run a 6502 with an ESP32 -# as the only "peripheral" device. If emulate_memory is set to False, -# this monitor can be used to monitor the bus lines between a 6502 -# and an actual memory chip. -emulate_memory = True - -# Thin wrapper taking care of switching I/O mode of Pins. -class Pin: - def __init__(self, pin): - self.pin = pin - - def low(self): - p = machine.Pin(self.pin, machine.Pin.OUT) - p.off() - - def high(self): - p = machine.Pin(self.pin, machine.Pin.OUT) - p.on() - - def set(self, value): - p = machine.Pin(self.pin, machine.Pin.OUT) - if value == 0: - p.off() - else: - p.on() - - def read(self): - p = machine.Pin(machine.Pin.IN, machine.Pin.PULL_UP) - return p.value() - -def read_address_bus(): - rw = RW.read() - data = 0 - for p in reversed(A): - data = ((data << 1) + p.read()) - A.reverse() - return (rw, data) - -def read_data_bus(): - data = 0 - for p in reversed(D): - data = ((data << 1) + p.read()) - return data - -def write_data_bus(data): - data = 0 - for p in D: - p.set(data & 1) - data = data >> 1 - -def pp_mem(start, end): - """Pretty print memory content""" - print(' 0 1 2 3 4 5 6 7 8 9 A B C D E F') - for chunk in range(start//0x100*0x100, end+1, 16): - l = "{:04X}: ".format(chunk) - l += " ".join(["{:02X}".format(x) - for x in mem[chunk:min(chunk+16, end+1)]]) - print(l) - -def update_buses_and_print_state(end='\n'): - (rw, address) = read_address_bus() - # Get/set data bus and print command prompt - if rw: - format_string = "{address:04X} > {data:02X}" - else: - format_string = "{address:04X} < {data:02X}" - if rw and emulate_memory: - # CPU wants to read memory, and we - # emulate the memory. Therefore we - # answer this request - data = mem[address] - write_data_bus(data) - else: - # This is either a memory write operation or - # a memory read operation answered by the - # actual memory, not our emulation. - # Therefore we read the data from the bus. - data = read_data_bus() - mem[address] = data - print(format_string.format(address=address, data=data), end=end, flush=True) - -def tick(): - # Execute on CPU cycle with a clock frequency of 500 Hz or - # less. - PHI2.low() - time.sleep(.001) - PHI2.high() - time.sleep(.001) - -def run(cycles): - # Run for a number of cycles. This function is calle from rep. - # Since the buses' states are printed at the begin of each - # loop, it is not printed here for the final cycle. - assert(cycles > 0) - for _ in range(cycles-1): - tick() - update_buses_and_print_state() - tick() - -def warn_if_memory_not_emulated(): - if not emulate_memory: - print('WARNING: Memory not emulated; monitoring buses only.') - - -def print_help_msg(): - print("""\ -Commands: -r: Reset -<n>: Run for n clock cycles (empty = 1 cycle) -m <addr> [<data>]: Write to emulated RAM -d <from> <to>: Dump emulated RAM -w <filename>: Write emulated RAM to file -l <filename>: Load emulated RAM from file -b <filename>: Execute batch file -n: RAM emulation off: No bus write operations, listen only -e: RAM emulation on: Write from emulated memory to data bus -h: This information -x: Exit -""") - -def repl(script=[]): - # Get and parse next command - global mem - global emulate_memory - update_buses_and_print_state(end='') - if len(script) == 0: - print(": ", end='', flush=True) - l = sys.stdin.readline()[:-1] - else: - print(": {}".format(script[0]), flush=True) - l = script[0] - script = script[1:] - # Filter out comments - comment_start = l.find('#') - if comment_start != -1: - l = l[:comment_start] - # Tokenize input - l = l.split(" ") - cmd = l[0] - args = l[1:] - # Empty command = run for one clock cycle - if(len(cmd) == 0): - cmd = '1' - if cmd.isdigit(): - # Run for a number of cycles - run(int(cmd, 16)) - elif cmd == 'r': - # Reset - RST.low() - print('RST low') - run(2) - update_buses_and_print_state() - RST.high() - print('RST high') - run(7) - elif cmd == 'm': - # Write to emulated RAM - warn_if_memory_not_emulated() - addr = int(args[0], 16) - data = list(map(lambda x: int(x, 16), args[1:])) - mem[addr:addr+len(data)] = data - elif cmd == 'd': - # Dump emulated RAM - warn_if_memory_not_emulated() - pp_mem(int(args[0], 16), int(args[1], 16)) - elif cmd == 'w': - # Write emulated RAM to file - warn_if_memory_not_emulated() - with open(args[0], 'wb') as f: - f.write(mem) - elif cmd == 'l': - # Read emulated RAM from file - warn_if_memory_not_emulated() - with open(args[0], 'rb') as f: - mem = bytearray(f.read()) - elif cmd == 'b': - # Execute batch file - with open(args[0], 'rt') as f: - script = f.read().split('\n') - elif cmd == 'n': - # Turn RAM emulation off - emulate_memory = False - print('Memory emulation off; listening to buses only.') - elif cmd == 'e': - # Turn RAM emulation on - emulate_memory = True - print('Memory emulation on.') - elif cmd == 'h': - print_help_msg() - elif cmd == 'x': - # Exit - sys.exit(0) - else: - print('Unknown command') - repl(script) - -if __name__ == '__main__': - # Create objects for Pins - A = list(map(Pin, A_Pins)) - D = list(map(Pin, D_Pins)) - (RW, PHI2, RST) = map(Pin, [RW_Pin, PHI2_Pin, RST_Pin]) - print("** 6502 Monitor **\n") - print_help_msg() - repl() diff --git a/README.txt b/README.txt @@ -0,0 +1 @@ +See doc/Documentation.txt diff --git a/doc/Documentation.txt b/doc/Documentation.txt @@ -0,0 +1,82 @@ +* GATE 2010 - An 8-Bit Computer + +** Main Components + +The computer is based on a 65C02 running at 1 Mhz with 32K RAM +(AS6C62256-55PCN) and 8 K EEPROM (AT28C64B-15PU). A W65C51N ACAI +provides a serial communication interface. Bus logic is provided by a +ATF16V8B EEPLD. The reset logic is based on a NE555 in a monostable +configuration (with a little help (an inverter of the AFT16V8B). + +See hw/bom.ods for details of the components. (This list also contains +components not used in the current design.) + +** Memory Map + +Lowest 32K are RAM, highest 8K are ROM. ACAI is in between. See +hw/bus_logic/BUS_LOGIC.PLD for details. + +** Directory Structure + +- doc/ - Documentation +- hw/ - Hardware description (pcb not complete yet) +- misc/ - Miscellaneous files - See section Tools for a description +- roms/ - ROM images. See roms/ROMS.txt for a description. +- sw/ - "Userland" software to be loaded into RAM by a suitable ROM. See + sw/SW.txt for a description. + +** Boot Sequence + +The ROM at roms/boot/boot loads data via the serial interface to RAM +starting at address $0300 and executes it. The first two bytes of the +transmission is the number of $100 byte blocks to be transmitted. Run +rom/boot/boot.py on the host PC to upload a program. + +** Tools + +Directory misc/ contains some tools and unfinished parts: + +*** 6502_monitor/ + +A ESP32 monitor for the 65C02. This project has never really been +completed, because it would require some level shifter between the +3.3v of the ESP32 and the 5v of the 65C02. + +*** clock_reset_attiny45/ + +Generates clocks at different speeds and provides a reset logic. The +clocks have been used in the early implementation phase, before +replacing it with a 1 Mhz packaged crystal. The reset logic was +replaced by a NE555 configured as a monostable multivibrator. + +*** sd_card/ + +So far, the computer system does not have storage. This directory +contains some experiments interfacing the SPI interface of an SD card. + +** TODOs + +*** Write library functions + +- String input via serial line +- Multiplication and division +- Random number generator +- CRC generator + +*** Improve file upload + +- Connect dtr and reset lines of usb2serial interface and use them to + trigger uploads. +- Speedup upload process by removing echo of uploaded bytes; use CRC + instead for integrity check. + +*** Write script to export library functions from boot ROM +*** Get some software running + +Candidates: + +- 10PRINT +- MicroChess + +*** Design PCB +*** Connect SD card diff --git a/doc/notizen.txt b/doc/notizen.txt @@ -0,0 +1,67 @@ +* Design + +See bus_logic/BUS_LOGIC.PLD for memory layout. + + + +http://wilsonminesco.com/6502primer/LogicFamilies.html: "You must have +a way to make sure RAM cannot be written when Ξ¦2 is low!" + +=> Write glue logic for rw: rw_ram = rw_cpu # !phi2 + +If this doesn't solve the problem: + +Alliance RAM data sheet: +"WE#, CE# must be high during all address transitions." +=> Wire both WE#, CE# to PLD. Perhaps add two NAND gates to slow signal down? + + +Allgemein zu Adress-Dekodierung: +http://wilsonminesco.com/6502primer/addr_decoding.html + +Also: Connect DTR to RTS + +* Parts list + +- Renesas RAM (32, 64 K) +- 64 K RAM +- 8, 16 K ROM +- GAL + + +* Links + +http://wilsonminesco.com/6502primer/ +https://www.grappendorf.net/projects/6502-home-computer/ + +* Tools + +** 6502_monitor + +Little tool to control the address and databus of a 6502. This allows +to run the 6502 without any additional peripheral. This is a +MicroPython script for the ESP32. The pin are connected as follows: + +- Address Bus (16 pins - only lower 14 connected) +- Data bus (8 pins) +- Clock (1 pin) +- R/W (1 pin) + +Note that ESP32 pins 34 to 39 are read only, pins 6 to 11 (SPI) and 34 +& 36 (UART) cannot be used, thus we have 24 pins available. Therefore +we only connect the lower 14 lines of the address bus. Actually, it +looks like PIN 10 can be used both as input and output. At least the +MCU did not crash ... + +See http://wilsonminesco.com/6502primer/MysteryPins.html and 65c02 +data sheet on how to connect the pins. + +** mem_monitor + +Little tool to read and write memory. Since we have 24 pins available +on the ESP32, we use one pin for E, and G. A not gate ensure that one +is turned on when the other is turned off. + +Note that IO0 must be pulled up (or at least not down) on power-up in +order to boot into MicroPython. + diff --git a/hw/bus_logic/BUS_LOGIC.PLD b/hw/bus_logic/BUS_LOGIC.PLD @@ -0,0 +1,94 @@ +Name BUS_LOGIC; +Partno ; +Revision 01; +Date 10/01/20; +Designer gb; +Company ; +Location None; +Assembly None; +Device g16v8a; + +/* Bus logic for 8 bit computer based on 65C02 + */ + +pin 1 = rwb; /* cpu_RWB */ +pin 2 = i0; /* cpu_A15 */ +pin 3 = i1; /* cpu_A14 */ +pin 4 = i2; /* cpu_A13 */ +pin 5 = i3; /* cpu_A12 */ +pin 6 = i4; /* cpu_A11 */ +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 14 = o2; /* acai_#cs0 */ +pin 15 = o3; /* ce (not assigned) */ +pin 16 = o4; /* ce (not assigned) */ +pin 17 = o5; /* ce (not assigned) */ +pin 18 = o6; /* #we */ +pin 19 = o7; /* cpu_RESB */ + +/* ROM (8k) + Address range: 0xe000 - 0xffff + Bit pattern: 0b111............. + */ + +o0 = (!i0 # !i1 # !i2); + +/* RAM (32k) + Address range: 0x0000 - 0x7fff + Bit pattern: 0b0............... + */ + +/* Connect a14 directly to ram_#ce */ + +/* ACIA (1k) + Address range: 0xdc00 - 0xdfff + Bit pattern: 0b110111.......... +*/ + +o2 = (!i0 # !i1 # i2 # !i3 # !i4 # !i5); + +/* TBA (1k) + Address range: 0xd800 - 0xdbff + Bit pattern: 0b110110.......... +*/ + +o3 = (!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); + + +/* Inverter + This is not part of the bus logic. + The reset logic needs an inverter. + We provide it here. +*/ + +o7 = !reset_in; + +/* +oe# and we# for the memory chips must be +qualified by phi - No memory access +in the first part of the cycle, while phi +is low. +*/ + +/* oe# */ +o1 = !phi # !rwb; + +/* we# */ +o6 = !phi # rwb; diff --git a/misc/6502_monitor/Makefile b/misc/6502_monitor/Makefile @@ -0,0 +1,7 @@ +all: install run + +install: + wb_ampy -p /dev/ttyUSB0 put monitor.py + wb_ampy -p /dev/ttyUSB0 reset +run: + konsole -e tio /dev/ttyUSB0 diff --git a/misc/6502_monitor/machine.py b/misc/6502_monitor/machine.py @@ -0,0 +1,22 @@ +# Dummy class to run ESP32 programs on normal PC + +import random + +class Pin(): + + OUT = 0 + IN = 1 + PULL_UP = 2 + + def __init__(self, pin, _direction, _pullup=False): + pass + + def on(self): + pass + + def off(self): + pass + + def value(self): + return random.choice([0, 1]) + diff --git a/misc/6502_monitor/monitor.py b/misc/6502_monitor/monitor.py @@ -0,0 +1,266 @@ +#!/usr/bin/env python3 +"""Monitor and control 6502 busses + +This program controls the busses (and other required signals like PHI2) +of a 6502 from an ESP32. + +IMPORTANT: + +--------------------------------------------------------------- +Remember that ESP32 operates on 3.3v while 6502 operates on 5V! +--------------------------------------------------------------- + +""" + +import sys +import machine +import time +#import pdb + +# Connect 6502 address bus (mostly) to left side of ESP32 +# Can I really use GPIO10? +# A14 & A15 not connect due to lack of GPIO pins +A_Pins = [36, 39, 34, 35, 32, 33, 25, 26, 27, 14, 12, 13, 10, 15] +D_Pins = [2, 0, 4, 16, 17, 5, 18, 19] +RW_Pin = 21 +PHI2_Pin = 22 +RST_Pin = 23 + +# Max memory size is 2**14, because due to a lack of GPIO pins, only +# A0..A13 are connected +MEM_SIZE = 2**14 +mem = bytearray(b'\xea' * MEM_SIZE) +# By default, we emulate memory. This allows to run a 6502 with an ESP32 +# as the only "peripheral" device. If emulate_memory is set to False, +# this monitor can be used to monitor the bus lines between a 6502 +# and an actual memory chip. +emulate_memory = True + +# Thin wrapper taking care of switching I/O mode of Pins. +class Pin: + def __init__(self, pin): + self.pin_number = pin + self.mode = None + self.set_mode(machine.Pin.IN) + + def set_mode(self, mode): + if self.mode != mode: + self.mode = mode + if self.mode == machine.Pin.IN: + self.pin = machine.Pin(self.pin_number, self.mode, + machine.Pin.PULL_UP) + else: + self.pin = machine.Pin(self.pin_number, self.mode) + # time.sleep(.01) + + def low(self): + self.set_mode(machine.Pin.OUT) + self.pin.off() + + def high(self): + self.set_mode(machine.Pin.OUT) + self.pin.on() + + def set(self, value): + self.set_mode(machine.Pin.OUT) + if value == 0: + self.pin.off() + else: + self.pin.on() + + def read(self): + self.set_mode(machine.Pin.IN) + return self.pin.value() + +def read_address_bus(): + rw = RW.read() + data = 0 + for p in reversed(A): + data = ((data << 1) + p.read()) + return (rw, data) + +def read_data_bus(): + data = 0 + for p in reversed(D): + data = ((data << 1) + p.read()) + return data + +def write_data_bus(data): + for p in D: + p.set(data & 1) + data = data >> 1 + +def pp_mem(start, end): + """Pretty print memory content""" + print_flush(' 0 1 2 3 4 5 6 7 8 9 A B C D E F') + for chunk in range(start//0x100*0x100, end+1, 16): + l = "{:04X}: ".format(chunk) + l += " ".join(["{:02X}".format(x) + for x in mem[chunk:min(chunk+16, end+1)]]) + print_flush(l) + +def update_buses_and_print_state(end='\n'): + (rw, address) = read_address_bus() + # Get/set data bus and print command prompt + if rw: + format_string = "{address:04X} > {data:02X}" + else: + format_string = "{address:04X} < {data:02X}" + if rw and emulate_memory: + # CPU wants to read memory, and we + # emulate the memory. Therefore we + # answer this request + data = mem[address] + write_data_bus(data) + else: + # This is either a memory write operation or + # a memory read operation answered by the + # actual memory, not our emulation. + # Therefore we read the data from the bus. + data = read_data_bus() + mem[address] = data + print_flush(format_string.format(address=address, data=data), end=end) + +def tick(): + # Execute on CPU cycle with a clock frequency of 500 Hz or + # less. + PHI2.low() + #time.sleep(.001) + PHI2.high() + #time.sleep(.001) + +def run(cycles): + # Run for a number of cycles. This function is calle from rep. + # Since the buses' states are printed at the begin of each + # loop, it is not printed here for the final cycle. + assert(cycles > 0) + for _ in range(cycles-1): + tick() + update_buses_and_print_state() + tick() + +def warn_if_memory_not_emulated(): + if not emulate_memory: + print_flush('WARNING: Memory not emulated; monitoring buses only.') + + +def print_help_msg(): + print_flush("""\ +Commands: +r: Reset +<n>: Run for n clock cycles (empty = 1 cycle) +m <addr> [<data>]: Write to emulated RAM +d <from> <to>: Dump emulated RAM +w <filename>: Write emulated RAM to file +l <filename>: Load emulated RAM from file +b <filename>: Execute batch file +n: RAM emulation off: No bus write operations, listen only +e: RAM emulation on: Write from emulated memory to data bus +h: This information +x: Exit +""") + +def print_flush(*args, **kwargs): + # MicroPython does not support flush=True, therefore + # we use this little wrapper + if esp32: + print(*args, **kwargs) + else: + print(*args, **kwargs, flush=True) + +def repl(script=[]): + global mem + global emulate_memory + while True: + update_buses_and_print_state(end='') + if len(script) == 0: + print_flush(": ", end='') + l = "" + while True: + c = sys.stdin.read(1) + if esp32: + print_flush(c, end='') + if c == '\n': + break + l += c + else: + print_flush(": {}".format(script[0])) + l = script[0] + script = script[1:] + # Filter out comments + comment_start = l.find('#') + if comment_start != -1: + l = l[:comment_start] + # Tokenize input + l = l.split(" ") + cmd = l[0] + args = l[1:] + # Empty command = run for one clock cycle + if(len(cmd) == 0): + cmd = '1' + if cmd.isdigit(): + # Run for a number of cycles + run(int(cmd, 16)) + elif cmd == 'r': + # Reset + RST.low() + print_flush('RST low') + run(2) + update_buses_and_print_state() + RST.high() + print_flush('RST high') + run(7) + elif cmd == 'm': + # Write to emulated RAM + warn_if_memory_not_emulated() + addr = int(args[0], 16) + data = list(map(lambda x: int(x, 16), args[1:])) + mem[addr:addr+len(data)] = bytearray(data) + elif cmd == 'd': + # Dump emulated RAM + warn_if_memory_not_emulated() + pp_mem(int(args[0], 16), int(args[1], 16)) + elif cmd == 'w': + # Write emulated RAM to file + warn_if_memory_not_emulated() + with open(args[0], 'wb') as f: + f.write(mem) + elif cmd == 'l': + # Read emulated RAM from file + warn_if_memory_not_emulated() + with open(args[0], 'rb') as f: + mem = bytearray(f.read()) + elif cmd == 'b': + # Execute batch file + with open(args[0], 'rt') as f: + script = f.read().split('\n') + elif cmd == 'n': + # Turn RAM emulation off + emulate_memory = False + print_flush('Memory emulation off; listening to buses only.') + elif cmd == 'e': + # Turn RAM emulation on + emulate_memory = True + print_flush('Memory emulation on.') + elif cmd == 'h': + print_help_msg() + elif cmd == 'x': + # Exit + sys.exit(0) + else: + print_flush('Unknown command') + +def m(): + global esp32 + esp32 = (sys.platform == 'esp32') + global A, D, RW, PHI2, RST + # Create objects for Pins + A = list(map(Pin, A_Pins)) + D = list(map(Pin, D_Pins)) + (RW, PHI2, RST) = map(Pin, [RW_Pin, PHI2_Pin, RST_Pin]) + print_flush("** 6502 Monitor **\n") + print_help_msg() + repl() + +if __name__ == '__main__': + m() diff --git a/misc/clock_reset_attiny45/Makefile b/misc/clock_reset_attiny45/Makefile @@ -0,0 +1,35 @@ +PRG = clock_and_reset +OBJ = clock_and_reset.c +AALPATH = /media/gb/m/projects/avr/ +LIBS = -L$(AALPATH)/libaal/ -L$(AALPATH)/libaal/32u4_usb_serial/ -laal_$(MCU_TARGET)_$(CLOCK) -lusb_serial_$(MCU_TARGET)_$(CLOCK) +DEFS = -std=gnu99 -g -Wall -O2 + +###################### +# Target Platform # +###################### + +#MCU_TARGET = atmega328p +#MCU_TARGET = arduino_uno +MCU_TARGET = attiny45 +#MCU_TARGET = arduino_pro_micro + +###################### +# Target Clock Speed # +###################### + +CLOCK = 1000000L +#CLOCK = 8000000L +#CLOCK = 16000000L + +###################### +# ISP # +###################### + +#PROGRAMMER = arduino # Direct upload to Arduino Uno +#PROGRAMMER = avrisp # Arduino as ISP +PROGRAMMER = usbasp # USB ASP Stick +#PROGRAMMER = avr109 # Direct upload to Arudino ProMicro + +############################################################### + +include $(AALPATH)/libaal/Makefile.common diff --git a/misc/clock_reset_attiny45/clock_and_reset.c b/misc/clock_reset_attiny45/clock_and_reset.c @@ -0,0 +1,52 @@ +#include <libaal.h> +#include <util/delay.h> + + +// 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); + SET_MODE_OUTPUT_DIGITAL(CONTACT_5_DDR_REG, + CONTACT_5_DDR_BIT); + 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); + uint8_t clock_counter = 0; + uint16_t reset_counter = RESET_DELAY; // power on reset + while (1){ + clock_counter++; + // Generate clock + DIGITAL_WRITE(CONTACT_2_PORT_REG, CONTACT_2_PORT_BIT, + (clock_counter & 0x01) >> 0); + DIGITAL_WRITE(CONTACT_3_PORT_REG, CONTACT_3_PORT_BIT, + (clock_counter & 0x02) >> 1); + DIGITAL_WRITE(CONTACT_5_PORT_REG, CONTACT_5_PORT_BIT, + (clock_counter & 0x04) >> 2); + // Has a reset been triggered? + if (!DIGITAL_READ(CONTACT_6_PIN_REG, + CONTACT_6_PIN_BIT)) { + reset_counter = 0x4F; + } + // If a reset has been triggered, keep the reset pin + // low for some time + if (reset_counter > 0) { + DIGITAL_WRITE(CONTACT_7_PORT_REG, CONTACT_7_PORT_BIT, + 0); + reset_counter--; + } + else { + DIGITAL_WRITE(CONTACT_7_PORT_REG, CONTACT_7_PORT_BIT, + 1); + } + _delay_ms(20); + } + return 1; // dummy +} diff --git a/misc/sd_card/card_info.csv b/misc/sd_card/card_info.csv @@ -0,0 +1,312 @@ +# See +# https://openlabpro.com/guide/interfacing-microcontrollers-with-sd-card/ +# http://www.dejazzer.com/ee379/lecture_notes/lec12_sd_card.pdf +# http://ugweb.cs.ualberta.ca/~c274/resources/hardware/SDcards/SD_SDIO_specsv1.pdf +#https://electronics.stackexchange.com/questions/375357/sd-card-initialization-problem-cmd16-wrong-response +#http://www.rjhcoding.com/avrc-sd-interface-1.php +http://chlazza.nfshost.com/sdcardinfo.html + + +# Time [s], Analyzer Name, Decoded Protocol Result + +0.000095041666667,SPI,MOSI: 0x74; MISO: 0xFF # CMD52 - IO_RW_DIRECT +0.000115083333333,SPI,MOSI: 0x80; MISO: 0xFF +0.000135083333333,SPI,MOSI: 0x00; MISO: 0xFF +0.000135083333333,SPI,MOSI: 0x00; MISO: 0xFF +0.000155083333333,SPI,MOSI: 0x0C; MISO: 0xFF +0.000175083333333,SPI,MOSI: 0x08; MISO: 0xFF +0.000195083333333,SPI,MOSI: 0x9F; MISO: 0xFF +0.000215083333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.000235083333333,SPI,MOSI: 0xFF; MISO: 0x04 # Answer + +0.000798041666667,SPI,MOSI: 0x40; MISO: 0xFF # CMD0 - GO_IDLE_STATE +0.000818041666667,SPI,MOSI: 0x00; MISO: 0xFF # Argument 0 +0.000838041666667,SPI,MOSI: 0x00; MISO: 0xFF # Argument 1 +0.000858041666667,SPI,MOSI: 0x00; MISO: 0xFF # Argument 2 +0.000878083333333,SPI,MOSI: 0x00; MISO: 0xFF # Argument 3 +0.000898083333333,SPI,MOSI: 0x95; MISO: 0xFF # CRC +0.000918083333333,SPI,MOSI: 0xFF; MISO: 0xFF # Dummy byte + +0.000938083333333,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.015663291666667,SPI,MOSI: 0x40; MISO: 0xFF # CMD0 - GO_IDLE_STATE +0.015683333333333,SPI,MOSI: 0x00; MISO: 0xFF # Argument 0 +0.015703333333333,SPI,MOSI: 0x00; MISO: 0xFF # Argument 1 +0.015723333333333,SPI,MOSI: 0x00; MISO: 0xFF # Argument 2 +0.015743333333333,SPI,MOSI: 0x00; MISO: 0xFF # Argument 3 +0.015763333333333,SPI,MOSI: 0x95; MISO: 0xFF # CRC +0.015783333333333,SPI,MOSI: 0xFF; MISO: 0xFF # Dummy byte + +0.015803375000000,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.035417000000000,SPI,MOSI: 0x48; MISO: 0xFF # CMD8 - SEND_IF_COND +0.035437000000000,SPI,MOSI: 0x00; MISO: 0xFF # Argument 0 +0.035457041666667,SPI,MOSI: 0x00; MISO: 0xFF # Argument 1 +0.035477041666667,SPI,MOSI: 0x01; MISO: 0xFF # Argument 2 +0.035497041666667,SPI,MOSI: 0xAA; MISO: 0xFF # Argument 3 +0.035517041666667,SPI,MOSI: 0x87; MISO: 0xFF # CRC +0.035537041666667,SPI,MOSI: 0xFF; MISO: 0xFF # Dummy byte + +0.035557041666667,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle +0.035577041666667,SPI,MOSI: 0xFF; MISO: 0x00 +0.035597083333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.035617083333333,SPI,MOSI: 0xFF; MISO: 0x01 +0.035637083333333,SPI,MOSI: 0xFF; MISO: 0xAA + +0.035871791666667,SPI,MOSI: 0x45; MISO: 0xFF # CMD5 - IO_SEND_OP_COND +0.035891791666667,SPI,MOSI: 0x00; MISO: 0xFF +0.035911833333333,SPI,MOSI: 0x00; MISO: 0xFF +0.035931833333333,SPI,MOSI: 0x00; MISO: 0xFF +0.035951833333333,SPI,MOSI: 0x00; MISO: 0xFF +0.035971833333333,SPI,MOSI: 0x5B; MISO: 0xFF +0.035991833333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.036011833333333,SPI,MOSI: 0xFF; MISO: 0x05 + +0.036242375000000,SPI,MOSI: 0x7B; MISO: 0xFF # CMD59 - CRC_ON_OFF +0.036262375000000,SPI,MOSI: 0x00; MISO: 0xFF +0.036282375000000,SPI,MOSI: 0x00; MISO: 0xFF +0.036302375000000,SPI,MOSI: 0x00; MISO: 0xFF +0.036322375000000,SPI,MOSI: 0x01; MISO: 0xFF # CRC on +0.036342416666667,SPI,MOSI: 0x83; MISO: 0xFF +0.036362416666667,SPI,MOSI: 0xFF; MISO: 0xFF + +0.036382416666667,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.036613916666667,SPI,MOSI: 0x77; MISO: 0xFF # CMD 55 - APP_CMD +0.036633916666667,SPI,MOSI: 0x00; MISO: 0xFF +0.036653916666667,SPI,MOSI: 0x00; MISO: 0xFF +0.036673916666667,SPI,MOSI: 0x00; MISO: 0xFF +0.036693916666667,SPI,MOSI: 0x00; MISO: 0xFF +0.036713958333333,SPI,MOSI: 0x65; MISO: 0xFF +0.036733958333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.036753958333333,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.036955458333333,SPI,MOSI: 0x69; MISO: 0xFF # ACMD41 - SD_SEND_OP_COND +0.036975458333333,SPI,MOSI: 0x40; MISO: 0xFF +0.036995458333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.037015500000000,SPI,MOSI: 0x80; MISO: 0xFF +0.037035500000000,SPI,MOSI: 0x00; MISO: 0xFF +0.037055500000000,SPI,MOSI: 0x17; MISO: 0xFF +0.037075500000000,SPI,MOSI: 0xFF; MISO: 0xFF + +0.037095500000000,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.045396416666667,SPI,MOSI: 0x77; MISO: 0xFF # CMD 55 - APP_CMD +0.045416416666667,SPI,MOSI: 0x00; MISO: 0xFF +0.045436416666667,SPI,MOSI: 0x00; MISO: 0xFF +0.045456416666667,SPI,MOSI: 0x00; MISO: 0xFF +0.045476416666667,SPI,MOSI: 0x00; MISO: 0xFF +0.045496416666667,SPI,MOSI: 0x65; MISO: 0xFF +0.045516416666667,SPI,MOSI: 0xFF; MISO: 0xFF + +0.045536458333333,SPI,MOSI: 0xFF; MISO: 0x01 # Response - Idle + +0.045734000000000,SPI,MOSI: 0x69; MISO: 0xFF # ACMD41 - SD_SEND_OP_COND +0.045754000000000,SPI,MOSI: 0x40; MISO: 0xFF +0.045774000000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.045794000000000,SPI,MOSI: 0x80; MISO: 0xFF +0.045814000000000,SPI,MOSI: 0x00; MISO: 0xFF +0.045834041666667,SPI,MOSI: 0x17; MISO: 0xFF +0.045854041666667,SPI,MOSI: 0xFF; MISO: 0xFF + +0.045874041666667,SPI,MOSI: 0xFF; MISO: 0x00 + +0.046096583333333,SPI,MOSI: 0x7A; MISO: 0xFF # CMD58 - READ_OCR +0.046116583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046136583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046156583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046176625000000,SPI,MOSI: 0x00; MISO: 0xFF +0.046196625000000,SPI,MOSI: 0xFD; MISO: 0xFF +0.046216625000000,SPI,MOSI: 0xFF; MISO: 0xFF + +0.046236625000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.046256625000000,SPI,MOSI: 0xFF; MISO: 0x80 +0.046276625000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.046296625000000,SPI,MOSI: 0xFF; MISO: 0x80 +0.046316666666667,SPI,MOSI: 0xFF; MISO: 0x00 + +0.046575458333333,SPI,MOSI: 0x4A; MISO: 0xFF # CMD10 - SEND_CID +0.046595458333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046615458333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046635458333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046655458333333,SPI,MOSI: 0x00; MISO: 0xFF +0.046675458333333,SPI,MOSI: 0x1B; MISO: 0xFF +0.046695458333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.046715500000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.046735500000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.046755500000000,SPI,MOSI: 0xFF; MISO: 0xFE +0.046775500000000,SPI,MOSI: 0xFF; MISO: 0x1B +0.046795500000000,SPI,MOSI: 0xFF; MISO: 0x53 +0.046815500000000,SPI,MOSI: 0xFF; MISO: 0x4D +0.046835541666667,SPI,MOSI: 0xFF; MISO: 0x30 +0.046855541666667,SPI,MOSI: 0xFF; MISO: 0x30 +0.046875541666667,SPI,MOSI: 0xFF; MISO: 0x30 +0.047044625000000,SPI,MOSI: 0xFF; MISO: 0x30 +0.047064625000000,SPI,MOSI: 0xFF; MISO: 0x30 +0.047084666666667,SPI,MOSI: 0xFF; MISO: 0x10 +0.047104666666667,SPI,MOSI: 0xFF; MISO: 0x1A +0.047124666666667,SPI,MOSI: 0xFF; MISO: 0x9F +0.047144666666667,SPI,MOSI: 0xFF; MISO: 0x59 +0.047164666666667,SPI,MOSI: 0xFF; MISO: 0x58 +0.047184666666667,SPI,MOSI: 0xFF; MISO: 0x00 +0.047204708333333,SPI,MOSI: 0xFF; MISO: 0xAC +0.047224708333333,SPI,MOSI: 0xFF; MISO: 0xDB +0.047244708333333,SPI,MOSI: 0xFF; MISO: 0x42 +0.047264708333333,SPI,MOSI: 0xFF; MISO: 0x13 + +0.047573750000000,SPI,MOSI: 0x49; MISO: 0xFF # CMD9 - SEND_CSD +0.047593791666667,SPI,MOSI: 0x00; MISO: 0xFF +0.047613791666667,SPI,MOSI: 0x00; MISO: 0xFF +0.047633791666667,SPI,MOSI: 0x00; MISO: 0xFF +0.047653791666667,SPI,MOSI: 0x00; MISO: 0xFF +0.047673791666667,SPI,MOSI: 0xAF; MISO: 0xFF +0.047693791666667,SPI,MOSI: 0xFF; MISO: 0xFF + +0.047713791666667,SPI,MOSI: 0xFF; MISO: 0x00 +0.047733833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.047753833333333,SPI,MOSI: 0xFF; MISO: 0xFE +0.047773833333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.047793833333333,SPI,MOSI: 0xFF; MISO: 0x7F +0.047813833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.047833833333333,SPI,MOSI: 0xFF; MISO: 0x32 +0.047853833333333,SPI,MOSI: 0xFF; MISO: 0x5B +0.047873875000000,SPI,MOSI: 0xFF; MISO: 0x5A +0.047968083333333,SPI,MOSI: 0xFF; MISO: 0x83 +0.047988125000000,SPI,MOSI: 0xFF; MISO: 0xBA +0.048008125000000,SPI,MOSI: 0xFF; MISO: 0xF6 +0.048028125000000,SPI,MOSI: 0xFF; MISO: 0xDB +0.048048125000000,SPI,MOSI: 0xFF; MISO: 0xDF +0.048068125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.048088125000000,SPI,MOSI: 0xFF; MISO: 0x0E +0.048108125000000,SPI,MOSI: 0xFF; MISO: 0x80 +0.048128166666667,SPI,MOSI: 0xFF; MISO: 0x00 +0.048148166666667,SPI,MOSI: 0xFF; MISO: 0xB5 +0.048168166666667,SPI,MOSI: 0xFF; MISO: 0x2F +0.048188166666667,SPI,MOSI: 0xFF; MISO: 0x8B + +0.048452666666667,SPI,MOSI: 0x50; MISO: 0xFF # CMD16 - SET_BLOCKLEN +0.048472666666667,SPI,MOSI: 0x00; MISO: 0xFF +0.048492708333333,SPI,MOSI: 0x00; MISO: 0xFF +0.048512708333333,SPI,MOSI: 0x02; MISO: 0xFF +0.048532708333333,SPI,MOSI: 0x00; MISO: 0xFF +0.048552708333333,SPI,MOSI: 0x15; MISO: 0xFF +0.048572708333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.048592708333333,SPI,MOSI: 0xFF; MISO: 0x00 + +0.048823166666667,SPI,MOSI: 0x77; MISO: 0xFF # CMD55 - APP_CMD +0.048843166666667,SPI,MOSI: 0x00; MISO: 0xFF +0.048863166666667,SPI,MOSI: 0x00; MISO: 0xFF +0.048883166666667,SPI,MOSI: 0x00; MISO: 0xFF +0.048903166666667,SPI,MOSI: 0x00; MISO: 0xFF +0.048923166666667,SPI,MOSI: 0x65; MISO: 0xFF +0.048943208333333,SPI,MOSI: 0xFF; MISO: 0xFF + +0.048963208333333,SPI,MOSI: 0xFF; MISO: 0x00 + +0.049160750000000,SPI,MOSI: 0x73; MISO: 0xFF # CMD1 - SEND_SCR +0.049180750000000,SPI,MOSI: 0x00; MISO: 0xFF +0.049200750000000,SPI,MOSI: 0x00; MISO: 0xFF +0.049220750000000,SPI,MOSI: 0x00; MISO: 0xFF +0.049240750000000,SPI,MOSI: 0x00; MISO: 0xFF +0.049260750000000,SPI,MOSI: 0xC7; MISO: 0xFF +0.049280791666667,SPI,MOSI: 0xFF; MISO: 0xFF + +0.049300791666667,SPI,MOSI: 0xFF; MISO: 0x00 + +0.049320791666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049340791666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049360791666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049380791666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049400791666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049420833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.049440833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.049460833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.049564125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049584125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049604125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049624125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049644166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049664166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049684166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049704166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.049806708333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.049826750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049846750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049866750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049886750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049906750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049926750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.049946750000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.050041333333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.050061333333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.050081333333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.050101333333333,SPI,MOSI: 0xFF; MISO: 0xFE +0.050121375000000,SPI,MOSI: 0xFF; MISO: 0x02 +0.050141375000000,SPI,MOSI: 0xFF; MISO: 0x25 +0.050161375000000,SPI,MOSI: 0xFF; MISO: 0x80 +0.050181375000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.050275958333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.050295958333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.050316000000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.050336000000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.050356000000000,SPI,MOSI: 0xFF; MISO: 0x4C +0.050376000000000,SPI,MOSI: 0xFF; MISO: 0xD7 +0.050704541666667,SPI,MOSI: 0x77; MISO: 0xFF +0.050724541666667,SPI,MOSI: 0x00; MISO: 0xFF +0.050744583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.050764583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.050784583333333,SPI,MOSI: 0x00; MISO: 0xFF +0.050804583333333,SPI,MOSI: 0x65; MISO: 0xFF +0.050824583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.050844583333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.051046083333333,SPI,MOSI: 0x73; MISO: 0xFF +0.051066083333333,SPI,MOSI: 0x00; MISO: 0xFF +0.051086083333333,SPI,MOSI: 0x00; MISO: 0xFF +0.051106125000000,SPI,MOSI: 0x00; MISO: 0xFF +0.051126125000000,SPI,MOSI: 0x00; MISO: 0xFF +0.051146125000000,SPI,MOSI: 0xC7; MISO: 0xFF +0.051166125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051186125000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.051206125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051226125000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051246166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051266166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051286166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051306166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051326166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051346166666667,SPI,MOSI: 0xFF; MISO: 0xFF +0.051441583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051461583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051481583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051501583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051521583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051541583333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051561625000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051581625000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051676208333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051696208333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051716208333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051736208333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051756250000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051776250000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051796250000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051816250000000,SPI,MOSI: 0xFF; MISO: 0xFF +0.051910833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051930833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051950833333333,SPI,MOSI: 0xFF; MISO: 0xFF +0.051970833333333,SPI,MOSI: 0xFF; MISO: 0xFE +0.051990833333333,SPI,MOSI: 0xFF; MISO: 0x02 +0.052010833333333,SPI,MOSI: 0xFF; MISO: 0x25 +0.052030875000000,SPI,MOSI: 0xFF; MISO: 0x80 +0.052050875000000,SPI,MOSI: 0xFF; MISO: 0x00 +0.052145458333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.052165458333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.052185458333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.052205458333333,SPI,MOSI: 0xFF; MISO: 0x00 +0.052225458333333,SPI,MOSI: 0xFF; MISO: 0x4C +0.052245500000000,SPI,MOSI: 0xFF; MISO: 0xD7 diff --git a/misc/sd_card/esp32_sdcard.py b/misc/sd_card/esp32_sdcard.py @@ -0,0 +1,14 @@ +# See +# https://github.com/micropython/micropython/blob/master/drivers/sdcard/sdcard.py +# for protocol + +# Mode = 0 +# CPOL = 0 (low idle) +# CPHA = 0 (first/raising edge) +import machine, uos +c = machine.SDCard(slot=2, sck=18, miso=19, mosi=23, cs=5, freq=2000000) +print(c.info()) +uos.mount(c, "/sd") +uos.listdir('/sd') + +# See card_info.csv for decoded protocol diff --git a/notizen.txt b/notizen.txt @@ -1,152 +0,0 @@ -* Design - -6502 + nvSRAM, Bus-Transceiver vor RAM und I/O-Pins - -(Bus-Transceiver vor RAM wirklich notwendig? -http://wilsonminesco.com/6502primer/LogicFamilies.html sagt nein) - -Wir brauche RAM sowohl bei $0000, wg. Zero-Page und Stack, als -auch bei $FFFA-$FFFF, weil dort Interrupt- und Reset-Vektoren erwartet -werden. Außerdem sollte die Bus-Logik mΓΆglichst einfach sein. - -Ganz wichtig: RAM Schreibzugriff darf erst ermΓΆglicht werden, wenn der -Takt High ist. Erst dann ist der Datenbus stabil! - -MΓΆgliche LΓΆsung: IO-Bereich wird angewΓ€hlt durch MSB Adresse = b10 -ist: -(A15 & ~A14) = ~(A15 ~& ~A14) = (A15 ~& (A14 ~& A14)) ~& (A15 ~& (A14 ~& A14)) -Besser wΓ€re, ein NAND-Gate weniger in der Kaskade zu haben. -Siehe http://wilsonminesco.com/6502primer/addr_decoding.html fΓΌr VorschlΓ€ge. - -Frage: Sind meine NAND-Chips schnell genug? Laut Datenblatt -(<https://docs.rs-online.com/d108/0900766b806350fe.pdf>) ist -Propagation Dealy Time 260ns. Bei 1 Mhz dauert ein Takt 1us = 1000ns. -Nach 500ns geht der Takt hoch. Speicherchip braucht ab ~OE 70 ns um Daten zu -liefern. Wenn nur ein Gate zwischen Takt hoch und Chip/Output enable -low, also 260 ns+ 70 ns = 340 ns. Sollte passen. - -Zusammenfassung: Max. 3 Gatter fΓΌr Adress-Kodierung, Takt high auf low -um Lese/Schreiboperationen zu ermΓΆglichen darf nur durch 1 Gatter -laufen. - - - -Problem: Meine NAND-Chips sind vermutlich zu langsam. (Siehe -https://docs.rs-online.com/d108/0900766b806350fe.pdf in Kombination -mit "Note that 100ns memory is not fast enough for 10MHz on a 6502! -..." http://wilsonminesco.com/6502primer/addr_decoding.html) - -Allgemein zu Adress-Dekodierung: -http://wilsonminesco.com/6502primer/addr_decoding.html - -Flashen des RAMs, indem ESP32 Datenbus ΓΌbernimmt und LDA-STA-Kaskaden -sendet. - - -Nicht Teil des Hardware-Designs, in Software umsetzen: -Serielle Kommunikation per Bit-Banging - - -* Bauteilliste - -- CPU - W65C02S6TPG-14 - https://www.mouser.de/ProductDetail/Western-Design-Center-WDC/W65C02S6TPG-14?qs=opBjA1TV903lvWo9AEKH5w%3D%3D -- Sockel CPU -- Sockel nvRAM -- Sockel Bus Transceiver -- nvSRAM - M48Z02-70PC1 - https://www.mouser.de/ProductDetail/STMicroelectronics/M48Z02-70PC1?qs=at%2FPaO0D8JYWx4lwBc2dJg%3D%3D - M48Z58Y-70PC1 - https://www.mouser.de/ProductDetail/STMicroelectronics/M48Z58Y-70PC1?qs=swDD%252BF%252Bps7f2yvdR7wWBQg%3D%3D - M48Z35-70PC1 - https://www.mouser.de/ProductDetail/STMicroelectronics/M48Z35-70PC1?qs=yAkVQ3mwCG1bjdHDg%2FtPWA%3D%3D -- Oszillator 1 MHz - https://www.mouser.de/ProductDetail/ECS/ECS-100A-010?qs=GxOUx7aO6nwDnc3%252B6Ta2Kw%3D%3DECS-100A-010 - -- Lochrasterplatine(n) -- IC-Zange - Aries T-90 - https://www.mouser.de/ProductDetail/Aries-Electronics/T-90?qs=WZRMhwwaLl%2FGFiSK29n7Tw%3D%3D -- Antistatik-Armband - SCS ECWS61M-1 - https://www.mouser.de/ProductDetail/SCS/ECWS61M-1?qs=atelM%2FHH1ECjg%252Bvoti9NeQ%3D%3D -- Kabel weiblich-weiblich -- Steckbrett -- Stiftleistungen als Socke fΓΌr ESP32 - 310-47-120-41-001000 - https://www.mouser.de/ProductDetail/Mill-Max/310-47-120-41-001000?qs=5aG0NVq1C4zOej%252BDTv0V5A== -- Abisolierzange -- EEPROM -- RAM -- DIP-Schalter -- 3,3 kOhm WiderstΓ€nde -- Reset-Logik - DS1813-5+ - https://www.mouser.de/ProductDetail/Maxim-Integrated/DS1813-5%2B?qs=Jw2w9zrI6w%2Fv9tYN5eKaiw%3D%3D -- I/O Chip - W65C51N6TPG-14 - https://eu.mouser.com/ProductDetail/Western-Design-Center-WDC/W65C51N6TPG-14?qs=AgbsAOSw7WDdUCKSkUixbw%3D%3D - -* Vorgehen - -- Schaltung entwerfen -- Mit Bus-Transceiver experimentieren -- Busmonitor schreiben: MCU-Programm zum Schreiben/Lesen von Datenbus und Takt -[Ab hier mit CPU] -- 6502 mit MCU verbinden & NOPs ausfΓΌhren, Busse - beobachten. -- Takt fΓΌr 6502 von Oszillator generieren lassen statt MCU -- 6502 mit MCU verbinden & Programm ausfΓΌhren, Busse - beobachten. -- RAM-Monitor schreiben: MCU-Programm zum Lesen & Schreiben von RAM. -- RAM mit MCU verbinden -- Flasher schreiben -- Programme schreiben, flashen, ausfΓΌhren - -* Weitere Kommentare - -Maßnahmen gegen statische Entladung treffen! Matte, Armband - - -* Offen Fragen - -Sprechen die ICs miteinander oder brauchen wir da noch Glue Logic? -Habe ich alle WiderstΓ€nde, die ich brauche? -Alle benΓΆtigten ICs? -Sockel fΓΌr alle ICs? -Wie viele redundante Chips kaufen (und welche?) - -* Links - -http://wilsonminesco.com/6502primer/ -https://www.grappendorf.net/projects/6502-home-computer/ - -* Tools - -** 6502_monitor - -Little tool to control the address and databus of a 6502. This allows -to run the 6502 without any additional peripheral. This is a -MicroPython script for the ESP32. The pin are connected as follows: - -- Address Bus (16 pins - only lower 14 connected) -- Data bus (8 pins) -- Clock (1 pin) -- R/W (1 pin) - -Note that ESP32 pins 34 to 39 are read only, pins 6 to 11 (SPI) and 34 -& 36 (UART) cannot be used, thus we have 24 pins available. Therefore -we only connect the lower 14 lines of the address bus. Actually, it -looks like PIN 10 can be used both as input and output. At least the -MCU did not crash ... - -See http://wilsonminesco.com/6502primer/MysteryPins.html and 65c02 -data sheet on how to connect the pins. - -** mem_monitor - -Little tool to read and write memory. Since we have 24 pins available -on the ESP32, we use one pin for E, and G. A not gate ensure that one -is turned on when the other is turned off. diff --git a/roms/ROMS.txt b/roms/ROMS.txt @@ -0,0 +1,25 @@ +boot/ + +This is the main "operating system" ROM. It provides some library +functions and most notably a mechanism to load software from the +serial interface into the RAM and execute it. + +nop/ + +Just a sequence of NOP instructions. Used to test if the CPU +interacts with the EEPROM. + +serial_char_out/ + +Outputs "A" to the serial interface in an endless loop. Used to test +if the CPU interacts with the ACAI W65C22. + +serial_echo/ + +Echos all characters input on the serial line. Used to test if the CPU +interacts with the ACAI W65C22. + +simple_loop/ + +Just endlessly jumping between memory locations. Used to test if the +CPU interacts with the EEPROM. diff --git a/roms/boot/Makefile b/roms/boot/Makefile @@ -0,0 +1,19 @@ +TARGET=boot +SYMON=java -jar ../../emulator/symon-1.3.1.jar -cpu 65c02 + +all: $(TARGET) $(TARGET)_symon + +$(TARGET): $(TARGET).s + xa -l $(TARGET).l -r -o $(TARGET) $< + +$(TARGET)_symon: $(TARGET).s + xa -DSYMON -l $(TARGET)_symon.l -r -o $(TARGET)_symon $< + +emulation: $(TARGET)_symon + $(SYMON) -cpu 65c02 -rom ./$(TARGET)_symon + +flash: $(TARGET) + sudo ~/opt/minipro-0.3/minipro -p AT28C64B -w $< + +clean: + rm -f $(TARGET) $(TARGET).l $(TARGET)_symon $(TARGET)_symon.l diff --git a/roms/boot/boot.py b/roms/boot/boot.py @@ -0,0 +1,68 @@ +#!/usr/bin/env python3 +"""Upload software to 8-bit computer""" + +import serial +import sys +import argparse +import time +import pdb + +SERIAL_PORT = '/dev/ttyUSB0' +SERIAL_SPEED = 19200 + +def test_serial_echo(): + with serial.Serial(SERIAL_PORT, SERIAL_SPEED) as s: + # Wait for '\n' + print("Reset 8-bit computer.") + s.readline() + print("Writing & reading 0x100 bytes.") + for i in range(0x00, 0x100): + # Serial echo may echo '\r' as '\r\n', therefore + # we omit it. + if i != 13: + print(".", end="", flush=True) + s.write(bytes([i])) + b = s.read(1) + if (ord(b) != i): + # pdb.set_trace() + print('\nExpected 0x{:02X}, got 0x{:02X}.'.format(i, ord(b))) + print() + + +def upload_program(filename): + with open(filename, 'rb') as f: + data = f.read() + # Pad to 256 byte block size + pad = 0x100 - (len(data) % 0x100) + if (pad != 0x100): + data = data + b'\x00'*pad + blocks = int(len(data) / 0x100) + with serial.Serial(SERIAL_PORT, SERIAL_SPEED) as s: + # Wait for '\n' + print("Reset 8-bit computer.") + s.readline() + time.sleep(1) + print("Uploading program.") + e = str.encode(chr(blocks)) + s.write(e) + r = s.read(1) + if (r != e): + print('\nERROR: Transmission failed. Expected 0x{:02X}, got 0x{:02X}.'.format(e, r)) + sys.exit(-1) + + for d in data: + print(".", end="", flush=True) + s.write(bytes([d])) + b = s.read(1) + if (ord(b) != d): + print('\nERROR: Transmission failed. Expected 0x{:02X}, got 0x{:02X}.'.format(d, ord(b))) + sys.exit(-1) + print('\nDone.') + +if __name__ == '__main__': + parser = argparse.ArgumentParser(description='Upload to 8-bit computer') + parser.add_argument('filename', metavar='FILENAME', type=str, + help='Program to upload') + args = parser.parse_args() + upload_program(filename=args.filename) + diff --git a/roms/boot/boot.s b/roms/boot/boot.s @@ -0,0 +1,279 @@ +;;; Receive data from termina. Store it in RAM & execute it. + +// #define BPS_300 +#define BPS_19200 + +#ifdef SYMON + * = $c000 ; Symon + acia_base = $8800 ; Symon +#else + * = $e000 + acia_base = $dc00 +#endif + acia_data_reg = acia_base + acia_status_reg = acia_base + 1 + acia_cmd_reg = acia_base + 2 + acia_ctrl_reg = acia_base + 3 + +;;; Function signatures and local variables + +;;; puts +;;; Input: +;;; puts_str, put_str+1: +;;; 2 bytes on zero page containing string address +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, puts_str, put_str+1 + + puts_str = $20 + +;;; putc +;;; Input: +;;; a: +;;; Character to be printed +;;; Output: +;;; - +;;; Changes: +;;; a, x, y + +;;; getc +;;; Input: +;;; a: +;;; Character to be send +;;; Output: +;;; - +;;; Changes: +;;; a + +init: + jsr init_acia +/* jsr count_hex + jsr memory_test + */ + jmp download_program + +count_hex: + lda #$00 +_count_hex_loop: + pha + jsr puth + pla + inc + bne _count_hex_loop + rts + +download_program: + ;; Print start banner + lda #<ready_str + sta puts_str + lda #>ready_str + sta puts_str+1 + jsr puts + ;; Get number of 0x100 byte blocks to be read + jsr getc + jsr putc + ;; We start write to $0300. Thus the last block + ;; is ($3 + a) * $100 + clc + adc #$03 + sta $12 + ;; Read n * 0x100 bytes from acia + ;; and store them at 0x0300.. + ;; We use address $10 to store the target + ;; address + lda #$00 + sta $10 + lda #$03 + sta $11 +transmit_block: + jsr getc + ldy #$00 + sta ($10), y + jsr putc + inc $10 + bne transmit_block + ;; Transmission of one block completed. + ;; If we are not done, increase + ;; MSB of target address and continue + inc $11 + lda $11 + cmp $12 + bne transmit_block + ;; Start program + jmp $0300 + +#define NL $0d, $0a +#define ZERO .byt $00 + +memory_test_pointer = $10 +memory_test: + lda #<memory_test_str + sta puts_str + lda #>memory_test_str + sta puts_str+1 + jsr puts + lda #$30 + sta memory_test_pointer + lda #$00 + sta memory_test_pointer+1 +loop: + // lda #'.' + // jsr putc + lda #$00 + lda (memory_test_pointer) + pha + sta (memory_test_pointer) + nop + nop + nop + nop + nop + nop + nop + nop + nop + nop + lda (memory_test_pointer) + cmp #$00 + bne memory_error + lda #$FF + sta (memory_test_pointer) + lda (memory_test_pointer) + cmp #$FF + bne memory_error +cont: + pla + sta (memory_test_pointer) + inc memory_test_pointer + bne loop +b0: + inc memory_test_pointer+1 + lda memory_test_pointer+1 + cmp #$80 + bne loop + lda #<memory_test_complete_str + sta puts_str + lda #>memory_test_complete_str + sta puts_str+1 + jsr puts + rts +memory_error: + pha + lda #<memory_error_str + sta puts_str + lda #>memory_error_str + sta puts_str+1 + jsr puts + jsr memory_print_location + pla + jsr puth + ;; NL + lda #$0d + jsr putc + lda #$0a + jsr putc + jmp cont + +memory_print_location: + lda memory_test_pointer+1 + jsr puth + lda memory_test_pointer + jsr puth + ;; NL + lda #$0d + jsr putc + lda #$0a + jsr putc + rts + + +memory_test_str: + .asc "Performing memory test ...", NL, $00 +memory_test_complete_str: + .asc "Memory test completed.", NL, $00 +memory_error_str: + .asc "Memory error!", NL, $00 +ready_str: + .asc "READY!", NL, $00 + +getc: + ;; Read character from acia + lda acia_status_reg + and #%00001000 + beq getc + lda acia_data_reg + rts + +endless_a: + lda #'A' + jsr putc + jmp endless_a + +puts: + ;; Send string terminated by '\0' + ldy #$00 +_puts_loop: + lda (puts_str), y + beq _puts_end + phy + jsr putc + ply + iny + jmp _puts_loop +_puts_end: + rts + +puth: + ;; Send a as hex number + pha + lsr + lsr + lsr + lsr + jsr _puth_nibble + pla + and #$0F + jsr _puth_nibble + rts +_puth_nibble: + clc + adc #$30 ; Decimal number + cmp #$3A ; >10 ? + bmi _puth_puts + adc #$26 +_puth_puts: + jsr putc + rts + +init_acia: + ;; Reset acai + sta acia_status_reg + lda #%00011111 ; 19200 bps, 8 data bits, 1 stop bit + sta acia_ctrl_reg + ;; No parity, no echo, no interrupts, DTR ready + lda #%11001011 + sta acia_cmd_reg + rts + + +putc: + ;; Send character + sta acia_data_reg + ;; Length of delay loop determined experimentally + ldx #$1 +_putc_wait_loop: + // ldy #$5e + ldy #$88 +_putc_inner_loop: + dey + bne _putc_inner_loop + dex + bne _putc_wait_loop + rts + + ;; Vectors + .dsb $fffa-*, $ff + .word $0000 ; nmi + .word init ; reset + .word $0000 ; irq diff --git a/roms/nop/nop.bin b/roms/nop/nop.bin @@ -0,0 +1 @@ +κκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκκ+ \ No newline at end of file diff --git a/roms/serial_char_out/Makefile b/roms/serial_char_out/Makefile @@ -0,0 +1,10 @@ +TARGET=serial_char_out + +all: $(TARGET).s + xa -o $(TARGET) $< + +flash: $(TARGET) + sudo ~/opt/minipro-0.3/minipro -p AT28C64B -w $< + +clean: + rm -f $(TARGET) diff --git a/roms/serial_char_out/count_receive_errors.py b/roms/serial_char_out/count_receive_errors.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python3 +"""Count receive errors.""" + +import pdb +import serial + +character = b'A' +block_size = 1000 +SERIAL_PORT = '/dev/ttyUSB0' +SERIAL_SPEED = 19200 + +with serial.Serial(SERIAL_PORT, SERIAL_SPEED) as s: + errors = 0 + total = 0 + while True: + for _ in range(block_size): + total += 1 + c = s.read(1) + if c != character: + # pdb.set_trace() + print('Got "{}"'.format(c)) + errors += 1 + print('{} errors of {} ({:01.4f} %)'.format(errors, total, + float(errors)/total)) + diff --git a/roms/serial_char_out/serial_char_out.s b/roms/serial_char_out/serial_char_out.s @@ -0,0 +1,51 @@ + ;; Output sequence of 'A' via ACIA 65C51 + +// #define SYMON + +#ifdef SYMON + * = $c000 ; Symon + acia_base = $8800 ; Symon +#else + * = $e000 + acia_base = $dc00 +#endif + acia_data_reg = acia_base + acia_status_reg = acia_base + 1 + acia_cmd_reg = acia_base + 2 + acia_ctrl_reg = acia_base + 3 + +init: + ;; Reset acai + sta acia_status_reg + ;; 300 bps, 8 data bits, 1 stop bit + lda #%00010110 + sta acia_ctrl_reg + ;; No parity, no echo, no interrupts, DTR ready + lda #%11001011 + sta acia_cmd_reg +send_loop: + lda #"A" + sta acia_data_reg + ;; 4 cycles per inner loop run + ;; At 1 Mhz and 300 bps, transmitting one bit + ;; takes 1*10**6/300 = 3333.3 cycles + ;; Including start bit and stop bit, we have + ;; to transmit 10 bit for 1 byte. + ;; Thus, we should run the loop for + ;; 3333.3*10/4 = 8333.25 0 $208d iterations. + ;; We run for 2100 iterations. + ldx #$21 ; 2 cycles +wait_loop: + ldy #$ff ; 2 cycles +inner_loop: + dey ; 2 cycles + bne inner_loop ; 2 cycles + dex ; 2 cycles + bne wait_loop ; 2 cycles + jmp send_loop ; 4 cycles + + ;; Vectors + .dsb $fffa-*, $ff + .word $0000 ; nmi + .word init ; reset + .word $0000 ; irq diff --git a/roms/serial_echo/Makefile b/roms/serial_echo/Makefile @@ -0,0 +1,15 @@ +TARGET=serial_echo +SYMON=java -jar ../../emulator/symon-1.3.1.jar + +all: $(TARGET).s + xa -o $(TARGET) $< + +emulation: $(TARGET).s + xa -DSYMON -o $(TARGET)_symon $< + $(SYMON) -rom ./$(TARGET)_symon + +upload: $(TARGET) + sudo ~/opt/minipro-0.3/minipro -p AT28C64B -w $< + +clean: + rm -f $(TARGET) $(TARGET)_symon diff --git a/roms/serial_echo/serial_echo.s b/roms/serial_echo/serial_echo.s @@ -0,0 +1,103 @@ + ;; Echo characters read via ACIA 65C51 + +// #define BPS_300 +#define BPS_19200 + +#ifdef SYMON + * = $c000 ; Symon + acia_base = $8800 ; Symon +#else + * = $e000 + acia_base = $dc00 +#endif + acia_data_reg = acia_base + acia_status_reg = acia_base + 1 + acia_cmd_reg = acia_base + 2 + acia_ctrl_reg = acia_base + 3 + +init: + ;; Reset acai + sta acia_status_reg +#ifdef BPS_300 + lda #%00010110 ; 300 bps, 8 data bits, 1 stop bit +#endif +#ifdef BPS_19200 + lda #%00011111 ; 19200 bps, 8 data bits, 1 stop bit +#endif + sta acia_ctrl_reg + ;; No parity, no echo, no interrupts, DTR ready + lda #%11001011 + sta acia_cmd_reg + ;; Print banner + lda #'R' + jsr send_char + lda #'E' + jsr send_char + lda #'A' + jsr send_char + lda #'D' + jsr send_char + lda #'Y' + jsr send_char + lda #'.' + jsr send_char + lda #$0d ; '\r' + jsr send_char + lda #$0a ; '\n' + jsr send_char +read_write_loop: + jsr receive_char + ;; Replace '\r' by '\r\n' + cmp #$0d ; '\r' + bne normal_char + lda #$0a ; '\n' + jsr send_char + lda #$0d ; '\r' + jsr send_char + jmp read_write_loop +normal_char: + jsr send_char + jmp read_write_loop + +receive_char: + ;; Read character from acia + lda acia_status_reg + and #%00001000 + beq receive_char + lda acia_data_reg + rts + +send_char: + ;; Send character + sta acia_data_reg + ;; 4 cycles per inner loop run +#ifdef BPS_300 + ;; At 1 Mhz and 300 bps, transmitting one bit + ;; takes 1*10**6/300 = 3333.3 cycles + ;; Including start bit and stop bit, we have + ;; to transmit 10 bit for 1 byte. + ;; Thus, we should run the loop for + ;; 3333.3*10/4 = 8333.25 0 $208d iterations. + ;; We run for 2100 iterations. + ldx #$21 ; 2 cycles +wait_loop: + ldy #$ff ; 2 cycles +#endif +#ifdef BPS_19200 + ;; 1*10**6/19200*10/4 = 130.21 + ldx #$01 ; 2 cycles +wait_loop: + ldy #$88 ; 2 cycles +#endif +inner_loop: + dey ; 2 cycles + bne inner_loop ; 2 cycles + dex ; 2 cycles + bne wait_loop ; 2 cycles + rts + + ;; Vectors + .dsb $fffa-*, $ff + .word $0000 ; nmi + .word init ; reset + .word $0000 ; irq diff --git a/roms/simple_loop/Makefile b/roms/simple_loop/Makefile @@ -0,0 +1,10 @@ +TARGET=loop + +$TARGET: $(TARGET).s + xa -o $(TARGET) $< + +upload: $(TARGET) + sudo ~/opt/minipro-0.3/minipro -p AT28C64B -w $< + +clean: + rm -f $(TARGET) diff --git a/roms/simple_loop/loop.s b/roms/simple_loop/loop.s @@ -0,0 +1,16 @@ + * = $e000 ; ROM starts here +start: + jmp middle + + .dsb $e010-*, $ff +middle: + jmp high + + .dsb $e100-*, $ff +high: jmp start + + ;; Vectors + .dsb $fffa-*, $ff + .word $0000 ; nmi + .word start ; reset + .word $0000 ; irq diff --git a/skizze.kra b/skizze.kra Binary files differ. diff --git a/sw/SW.txt b/sw/SW.txt @@ -0,0 +1,4 @@ +mem_test/ + +Tests RAM write and read operations. Used to test if the CPU interacts +with the RAM. diff --git a/sw/mem_test/Makefile b/sw/mem_test/Makefile @@ -0,0 +1,15 @@ +TARGET=mem_test + +all: $(TARGET) $(TARGET)_symon + +$(TARGET): $(TARGET).s + xa -l $(TARGET).l -r -o $(TARGET) $< + +$(TARGET)_symon: $(TARGET).s + xa -DSYMON -l $(TARGET)_symon.l -r -o $(TARGET)_symon $< + +upload: $(TARGET) + ../../roms/boot/boot.py $(TARGET) + +clean: + rm -f $(TARGET) $(TARGET)_symon $(TARGET).l $(TARGET)_symon.l diff --git a/sw/mem_test/liba.h b/sw/mem_test/liba.h @@ -0,0 +1,123 @@ +;;; Function signatures and local variables + +;;; init_acia +;;; Initialize acai for communication +;;; Input: +;;; - +;;; Output: +;;; - +;;; Changes: +;;; a, acai-registers + +#ifdef SYMON + acia_base = $8800 ; Symon +#else + acia_base = $dc00 +#endif + acia_data_reg = acia_base + acia_status_reg = acia_base + 1 + acia_cmd_reg = acia_base + 2 + acia_ctrl_reg = acia_base + 3 + +;;; puts +;;; Send up to 256 characters terminated by null via acia +;;; Input: +;;; puts_str, put_str+1: +;;; 2 bytes on zero page containing string address +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, puts_str, put_str+1 + + puts_str = $10 + +;;; putc +;;; Send character via acia +;;; Input: +;;; a: +;;; Character to be printed +;;; Output: +;;; - +;;; Changes: +;;; x, acai-registers + +;;; puth +;;; Convert byte two hex and send via acia +;;; Input: +;;; a: +;;; Byte to be printed +;;; Output: +;;; - +;;; Changes: +;;; a, x, acai-registers, c-flag + +;;; putnl +;;; Send newline via acia +;;; Input: +;;; - +;;; Output: +;;; - +;;; Changes: +;;; a + +;;; Macros + +;;; PRINT(addr) +;;; Send zero terminated string at addr via acia. +;;; Input: +;;; addr: +;;; Address of zero terminated string (<= 256 characters) +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, puts_str, put_str+1 + +;;; PRINTS(string) (<= 255 characters) +;;; Send string via acia +;;; Input: +;;; string: +;;; String to be send. +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, puts_str, put_str+1 + +;;; PRINTSNL(string) (<= 253 characters) +;;; Send string and newline via acia +;;; Input: +;;; string: +;;; String to be send. +;;; Output: +;;; - +;;; Changes: +;;; a, x, y, puts_str, put_str+1 + + + +#define PRINT(addr) \ + .(: \ + lda #<addr: \ + sta puts_str: \ + lda #>addr: \ + sta puts_str+1: \ + jsr puts: \ + .) + +#define PRINTS(string) \ + .(: \ + PRINT(saddr): \ + jmp cont: \ +saddr: \ + .asc string, $00:\ +cont: \ + .) + +#define PRINTSNL(string) \ + .(: \ + PRINT(saddr): \ + jmp cont: \ +saddr: \ + .asc string, $0d, $0a, $00:\ +cont: \ + .) + diff --git a/sw/mem_test/liba.s b/sw/mem_test/liba.s @@ -0,0 +1,60 @@ +init_acia: + ;; Reset acai + sta acia_status_reg + lda #%00011111 ; 19200 bps, 8 data bits, 1 stop bit + sta acia_ctrl_reg + ;; No parity, no echo, no interrupts, DTR ready + lda #%11001011 + sta acia_cmd_reg + rts + +puts: + ;; Send string terminated by '\0' + ldy #$00 +_puts_loop: + lda (puts_str), y + beq _puts_end + jsr putc + iny + jmp _puts_loop +_puts_end: + rts + +putc: + ;; Send character + sta acia_data_reg + ;; Length of delay loop determined experimentally + ldx #$88 +_putc_loop: + dex + bne _putc_loop + rts + +puth: + ;; Send a as hex number + pha + lsr + lsr + lsr + lsr + jsr _puth_nibble + pla + and #$0F + jsr _puth_nibble + rts +_puth_nibble: + clc + adc #$30 ; Decimal number + cmp #$3A ; >10 ? + bmi _puth_putc + adc #$26 +_puth_putc: + jsr putc + rts + +putnl: + lda #$0d + jsr putc + lda #$0a + jsr putc + rts diff --git a/sw/mem_test/mem_test.s b/sw/mem_test/mem_test.s @@ -0,0 +1,59 @@ +#include "liba.h" + + * = $0300 +init: + .( + jsr init_acia +loop: + jsr mem_test +end: + jmp loop + // jmp end + .) + +mem_test: + .( + PRINTSNL("Memory test") + ;; Address to be tested is stored as 16 bit value at $40. + ;; We start the memory test at address $0400. + ;; The test runs up to $8000. It fails at the last address, + ;; because memory ends at $7fff. + start = $0400 + lda #<start + sta $40 + lda #>start + sta $41 +loop: + jsr mem_cell_test + inc $40 + bne loop + inc $41 + lda $41 + cmp #$80 + bne loop + rts + +mem_cell_test: + lda $41 + jsr puth + lda $40 + jsr puth + lda #$00 + sta ($40) + lda ($40) + cmp #$00 + bne fail + lda #$ff + sta ($40) + lda ($40) + cmp #$ff + bne fail + PRINTSNL(" OK") + rts +fail: + PRINTSNL(" Fail!") + rts + .) + + +#include "liba.s"