From d2385a9d3f134d76b93469c09dab4290e5d64c2e Mon Sep 17 00:00:00 2001 From: Stefano Furiosi Date: Sun, 12 Feb 2017 18:53:33 -0800 Subject: [PATCH] Cleanup & Add more comments --- ASM/woz_monitor_dasm.asm | 258 +++++++++++++++++++++++++++++++++++++++ ASM/woz_monitor_masm.asm | 258 --------------------------------------- README.md | 7 +- src/main.cpp | 47 +++++-- 4 files changed, 301 insertions(+), 269 deletions(-) create mode 100644 ASM/woz_monitor_dasm.asm delete mode 100644 ASM/woz_monitor_masm.asm diff --git a/ASM/woz_monitor_dasm.asm b/ASM/woz_monitor_dasm.asm new file mode 100644 index 0000000..5cdb065 --- /dev/null +++ b/ASM/woz_monitor_dasm.asm @@ -0,0 +1,258 @@ +; dasm woz_monitor_masm.asm -orom.o -lrom.lst -srom.sym + +;------------------------------------------------------------------------- +; +; The WOZ Monitor for the Apple 1 +; Written by Steve Wozniak 1976 +; +;------------------------------------------------------------------------- + + processor 6502 + org $FF00 + +;------------------------------------------------------------------------- +; Memory declaration +;------------------------------------------------------------------------- + +XAML equ $24 ;Last "opened" location Low +XAMH equ $25 ;Last "opened" location High +STL equ $26 ;Store address Low +STH equ $27 ;Store address High +L equ $28 ;Hex value parsing Low +H equ $29 ;Hex value parsing High +YSAV equ $2A ;Used to see if hex value is given +MODE equ $2B ;$00=XAM, $7F=STOR, $AE=BLOCK XAM + +IN equ $0200,$027F ;Input buffer + +KBD equ $D010 ;PIA.A keyboard input +KBDCR equ $D011 ;PIA.A keyboard control register +DSP equ $D012 ;PIA.B display output register +DSPCR equ $D013 ;PIA.B display control register + +; KBD b7..b0 are inputs, b6..b0 is ASCII input, b7 is constant high +; Programmed to respond to low to high KBD strobe +; DSP b6..b0 are outputs, b7 is input +; CB2 goes low when data is written, returns high when CB1 goes high +; Interrupts are enabled, though not used. KBD can be jumpered to IRQ, +; whereas DSP can be jumpered to NMI. + +;------------------------------------------------------------------------- +; Constants +;------------------------------------------------------------------------- + +BS equ $DF ;Backspace key, arrow left key +CR equ $8D ;Carriage Return +ESC equ $9B ;ESC key +PROMPT equ $5C ;Prompt character \ + +;------------------------------------------------------------------------- +; Let's get started +; +; Remark the RESET routine is only to be entered by asserting the RESET +; line of the system. This ensures that the data direction registers +; are selected. +;------------------------------------------------------------------------- + +RESET cld ;Clear decimal arithmetic mode + cli + ldy #%01111111 ;Mask for DSP data direction reg + sty DSP ;(DDR mode is assumed after reset) + lda #%10100111 ;KBD and DSP control register mask + sta KBDCR ;Enable interrupts, set CA1, CB1 for + sta DSPCR ;positive edge sense/output mode. + +; Program falls through to the GETLINE routine to save some program bytes +; Please note that Y still holds $7F, which will cause an automatic Escape + +;------------------------------------------------------------------------- +; The GETLINE process +;------------------------------------------------------------------------- + +NOTCR cmp #BS ;Backspace key? + beq BACKSPACE ;Yes + cmp #ESC ;ESC? + beq ESCAPE ;Yes + iny ;Advance text index + bpl NEXTCHAR ;Auto ESC if line longer than 127 + +ESCAPE lda #PROMPT ;Print prompt character + jsr ECHO ;Output it. + +GETLINE lda #CR ;Send CR + jsr ECHO + + ldy #0+1 ;Start a new input line +BACKSPACE dey ;Backup text index + bmi GETLINE ;Oops, line's empty, reinitialize + +NEXTCHAR lda KBDCR ;Wait for key press + bpl NEXTCHAR ;No key yet! + lda KBD ;Load character. B7 should be '1' + sta IN,Y ;Add to text buffer + jsr ECHO ;Display character + cmp #CR + bne NOTCR ;It's not CR! + +; Line received, now let's parse it + + ldy #-1 ;Reset text index + lda #0 ;Default mode is XAM + tax ;X=0 + +SETSTOR asl ;Leaves $7B if setting STOR mode + +SETMODE sta MODE ;Set mode flags + +BLSKIP iny ;Advance text index + +NEXTITEM lda IN,Y ;Get character + cmp #CR + beq GETLINE ;We're done if it's CR! + cmp #"." + bcc BLSKIP ;Ignore everything below "."! + beq SETMODE ;Set BLOCK XAM mode ("." = $AE) + cmp #":" + beq SETSTOR ;Set STOR mode! $BA will become $7B + cmp #"R" + beq RUN ;Run the program! Forget the rest + stx L ;Clear input value (X=0) + stx H + sty YSAV ;Save Y for comparison + +; Here we're trying to parse a new hex value + +NEXTHEX lda IN,Y ;Get character for hex test + eor #$B0 ;Map digits to 0-9 + cmp #9+1 ;Is it a decimal digit? + bcc DIG ;Yes! + adc #$88 ;Map letter "A"-"F" to $FA-FF + cmp #$FA ;Hex letter? + bcc NOTHEX ;No! Character not hex + +DIG asl + asl ;Hex digit to MSD of A + asl + asl + + ldx #4 ;Shift count +HEXSHIFT asl ;Hex digit left, MSB to carry + rol L ;Rotate into LSD + rol H ;Rotate into MSD's + dex ;Done 4 shifts? + bne HEXSHIFT ;No, loop + iny ;Advance text index + bne NEXTHEX ;Always taken + +NOTHEX cpy YSAV ;Was at least 1 hex digit given? + beq ESCAPE ;No! Ignore all, start from scratch + + bit MODE ;Test MODE byte + bvc NOTSTOR ;B6=0 is STOR, 1 is XAM or BLOCK XAM + +; STOR mode, save LSD of new hex byte + + lda L ;LSD's of hex data + sta (STL,X) ;Store current 'store index'(X=0) + inc STL ;Increment store index. + bne NEXTITEM ;No carry! + inc STH ;Add carry to 'store index' high +TONEXTITEM jmp NEXTITEM ;Get next command item. + +;------------------------------------------------------------------------- +; RUN user's program from last opened location +;------------------------------------------------------------------------- + +RUN jmp (XAML) ;Run user's program + +;------------------------------------------------------------------------- +; We're not in Store mode +;------------------------------------------------------------------------- + +NOTSTOR bmi XAMNEXT ;B7 = 0 for XAM, 1 for BLOCK XAM + +; We're in XAM mode now + + ldx #2 ;Copy 2 bytes +SETADR lda L-1,X ;Copy hex data to + sta STL-1,X ; 'store index' + sta XAML-1,X ; and to 'XAM index' + dex ;Next of 2 bytes + bne SETADR ;Loop unless X = 0 + +; Print address and data from this address, fall through next bne. + +NXTPRNT bne PRDATA ;NE means no address to print + lda #CR ;Print CR first + jsr ECHO + lda XAMH ;Output high-order byte of address + jsr PRBYTE + lda XAML ;Output low-order byte of address + jsr PRBYTE + lda #":" ;Print colon + jsr ECHO + +PRDATA lda #" " ;Print space + jsr ECHO + lda (XAML,X) ;Get data from address (X=0) + jsr PRBYTE ;Output it in hex format +XAMNEXT stx MODE ;0 -> MODE (XAM mode). + lda XAML ;See if there's more to print + cmp L + lda XAMH + sbc H + bcs TONEXTITEM ;Not less! No more data to output + + inc XAML ;Increment 'examine index' + bne MOD8CHK ;No carry! + inc XAMH + +MOD8CHK lda XAML ;If address MOD 8 = 0 start new line + and #%00000111 + bpl NXTPRNT ;Always taken. + +;------------------------------------------------------------------------- +; Subroutine to print a byte in A in hex form (destructive) +;------------------------------------------------------------------------- + +PRBYTE pha ;Save A for LSD + lsr + lsr + lsr ;MSD to LSD position + lsr + jsr PRHEX ;Output hex digit + pla ;Restore A + +; Fall through to print hex routine + +;------------------------------------------------------------------------- +; Subroutine to print a hexadecimal digit +;------------------------------------------------------------------------- + +PRHEX and #%00001111 ;Mask LSD for hex print + ora #"0" ;Add "0" + cmp #"9"+1 ;Is it a decimal digit? + bcc ECHO ;Yes! output it + adc #6 ;Add offset for letter A-F + +; Fall through to print routine + +;------------------------------------------------------------------------- +; Subroutine to print a character to the terminal +;------------------------------------------------------------------------- + +ECHO bit DSP ;DA bit (B7) cleared yet? + bmi ECHO ;No! Wait for display ready + sta DSP ;Output character. Sets DA + rts + +;------------------------------------------------------------------------- +; Vector area +;------------------------------------------------------------------------- + + dc.w $0000 ;Unused, what a pity +NMI_VEC dc.w $0F00 ;NMI vector +RESET_VEC dc.w RESET ;RESET vector +IRQ_VEC dc.w $0000 ;IRQ vector + +;------------------------------------------------------------------------- diff --git a/ASM/woz_monitor_masm.asm b/ASM/woz_monitor_masm.asm deleted file mode 100644 index 8fc1cb7..0000000 --- a/ASM/woz_monitor_masm.asm +++ /dev/null @@ -1,258 +0,0 @@ -; dasm woz_monitor_masm.asm -orom.o -lrom.lst -srom.sym - -;------------------------------------------------------------------------- -; -; The WOZ Monitor for the Apple 1 -; Written by Steve Wozniak 1976 -; -;------------------------------------------------------------------------- - - processor 6502 - org $FF00 - -;------------------------------------------------------------------------- -; Memory declaration -;------------------------------------------------------------------------- - -XAML equ $24 ;Last "opened" location Low -XAMH equ $25 ;Last "opened" location High -STL equ $26 ;Store address Low -STH equ $27 ;Store address High -L equ $28 ;Hex value parsing Low -H equ $29 ;Hex value parsing High -YSAV equ $2A ;Used to see if hex value is given -MODE equ $2B ;$00=XAM, $7F=STOR, $AE=BLOCK XAM - -IN equ $0200,$027F ;Input buffer - -KBD equ $D010 ;PIA.A keyboard input -KBDCR equ $D011 ;PIA.A keyboard control register -DSP equ $D012 ;PIA.B display output register -DSPCR equ $D013 ;PIA.B display control register - -; KBD b7..b0 are inputs, b6..b0 is ASCII input, b7 is constant high -; Programmed to respond to low to high KBD strobe -; DSP b6..b0 are outputs, b7 is input -; CB2 goes low when data is written, returns high when CB1 goes high -; Interrupts are enabled, though not used. KBD can be jumpered to IRQ, -; whereas DSP can be jumpered to NMI. - -;------------------------------------------------------------------------- -; Constants -;------------------------------------------------------------------------- - -BS equ $DF ;Backspace key, arrow left key -CR equ $8D ;Carriage Return -ESC equ $9B ;ESC key -PROMPT equ "\" ;Prompt character - -;------------------------------------------------------------------------- -; Let's get started -; -; Remark the RESET routine is only to be entered by asserting the RESET -; line of the system. This ensures that the data direction registers -; are selected. -;------------------------------------------------------------------------- - -RESET CLD ;Clear decimal arithmetic mode - CLI - LDY #%01111111 ;Mask for DSP data direction reg - STY DSP ;(DDR mode is assumed after reset) - LDA #%10100111 ;KBD and DSP control register mask - STA KBDCR ;Enable interrupts, set CA1, CB1 for - STA DSPCR ;positive edge sense/output mode. - -; Program falls through to the GETLINE routine to save some program bytes -; Please note that Y still holds $7F, which will cause an automatic Escape - -;------------------------------------------------------------------------- -; The GETLINE process -;------------------------------------------------------------------------- - -NOTCR CMP #BS ;Backspace key? - BEQ BACKSPACE ;Yes - CMP #ESC ;ESC? - BEQ ESCAPE ;Yes - INY ;Advance text index - BPL NEXTCHAR ;Auto ESC if line longer than 127 - -ESCAPE LDA #PROMPT ;Print prompt character - JSR ECHO ;Output it. - -GETLINE LDA #CR ;Send CR - JSR ECHO - - LDY #0+1 ;Start a new input line -BACKSPACE DEY ;Backup text index - BMI GETLINE ;Oops, line's empty, reinitialize - -NEXTCHAR LDA KBDCR ;Wait for key press - BPL NEXTCHAR ;No key yet! - LDA KBD ;Load character. B7 should be '1' - STA IN,Y ;Add to text buffer - JSR ECHO ;Display character - CMP #CR - BNE NOTCR ;It's not CR! - -; Line received, now let's parse it - - LDY #-1 ;Reset text index - LDA #0 ;Default mode is XAM - TAX ;X=0 - -SETSTOR ASL ;Leaves $7B if setting STOR mode - -SETMODE STA MODE ;Set mode flags - -BLSKIP INY ;Advance text index - -NEXTITEM LDA IN,Y ;Get character - CMP #CR - BEQ GETLINE ;We're done if it's CR! - CMP #"." - BCC BLSKIP ;Ignore everything below "."! - BEQ SETMODE ;Set BLOCK XAM mode ("." = $AE) - CMP #":" - BEQ SETSTOR ;Set STOR mode! $BA will become $7B - CMP #"R" - BEQ RUN ;Run the program! Forget the rest - STX L ;Clear input value (X=0) - STX H - STY YSAV ;Save Y for comparison - -; Here we're trying to parse a new hex value - -NEXTHEX LDA IN,Y ;Get character for hex test - EOR #$B0 ;Map digits to 0-9 - CMP #9+1 ;Is it a decimal digit? - BCC DIG ;Yes! - ADC #$88 ;Map letter "A"-"F" to $FA-FF - CMP #$FA ;Hex letter? - BCC NOTHEX ;No! Character not hex - -DIG ASL - ASL ;Hex digit to MSD of A - ASL - ASL - - LDX #4 ;Shift count -HEXSHIFT ASL ;Hex digit left, MSB to carry - ROL L ;Rotate into LSD - ROL H ;Rotate into MSD's - DEX ;Done 4 shifts? - BNE HEXSHIFT ;No, loop - INY ;Advance text index - BNE NEXTHEX ;Always taken - -NOTHEX CPY YSAV ;Was at least 1 hex digit given? - BEQ ESCAPE ;No! Ignore all, start from scratch - - BIT MODE ;Test MODE byte - BVC NOTSTOR ;B6=0 is STOR, 1 is XAM or BLOCK XAM - -; STOR mode, save LSD of new hex byte - - LDA L ;LSD's of hex data - STA (STL,X) ;Store current 'store index'(X=0) - INC STL ;Increment store index. - BNE NEXTITEM ;No carry! - INC STH ;Add carry to 'store index' high -TONEXTITEM JMP NEXTITEM ;Get next command item. - -;------------------------------------------------------------------------- -; RUN user's program from last opened location -;------------------------------------------------------------------------- - -RUN JMP (XAML) ;Run user's program - -;------------------------------------------------------------------------- -; We're not in Store mode -;------------------------------------------------------------------------- - -NOTSTOR BMI XAMNEXT ;B7 = 0 for XAM, 1 for BLOCK XAM - -; We're in XAM mode now - - LDX #2 ;Copy 2 bytes -SETADR LDA L-1,X ;Copy hex data to - STA STL-1,X ; 'store index' - STA XAML-1,X ; and to 'XAM index' - DEX ;Next of 2 bytes - BNE SETADR ;Loop unless X = 0 - -; Print address and data from this address, fall through next BNE. - -NXTPRNT BNE PRDATA ;NE means no address to print - LDA #CR ;Print CR first - JSR ECHO - LDA XAMH ;Output high-order byte of address - JSR PRBYTE - LDA XAML ;Output low-order byte of address - JSR PRBYTE - LDA #":" ;Print colon - JSR ECHO - -PRDATA LDA #" " ;Print space - JSR ECHO - LDA (XAML,X) ;Get data from address (X=0) - JSR PRBYTE ;Output it in hex format -XAMNEXT STX MODE ;0 -> MODE (XAM mode). - LDA XAML ;See if there's more to print - CMP L - LDA XAMH - SBC H - BCS TONEXTITEM ;Not less! No more data to output - - INC XAML ;Increment 'examine index' - BNE MOD8CHK ;No carry! - INC XAMH - -MOD8CHK LDA XAML ;If address MOD 8 = 0 start new line - AND #%00000111 - BPL NXTPRNT ;Always taken. - -;------------------------------------------------------------------------- -; Subroutine to print a byte in A in hex form (destructive) -;------------------------------------------------------------------------- - -PRBYTE PHA ;Save A for LSD - LSR - LSR - LSR ;MSD to LSD position - LSR - JSR PRHEX ;Output hex digit - PLA ;Restore A - -; Fall through to print hex routine - -;------------------------------------------------------------------------- -; Subroutine to print a hexadecimal digit -;------------------------------------------------------------------------- - -PRHEX AND #%00001111 ;Mask LSD for hex print - ORA #"0" ;Add "0" - CMP #"9"+1 ;Is it a decimal digit? - BCC ECHO ;Yes! output it - ADC #6 ;Add offset for letter A-F - -; Fall through to print routine - -;------------------------------------------------------------------------- -; Subroutine to print a character to the terminal -;------------------------------------------------------------------------- - -ECHO BIT DSP ;DA bit (B7) cleared yet? - BMI ECHO ;No! Wait for display ready - STA DSP ;Output character. Sets DA - RTS - -;------------------------------------------------------------------------- -; Vector area -;------------------------------------------------------------------------- - - dc.w $0000 ;Unused, what a pity -NMI_VEC dc.w $0F00 ;NMI vector -RESET_VEC dc.w RESET ;RESET vector -IRQ_VEC dc.w $0000 ;IRQ vector - -;------------------------------------------------------------------------- diff --git a/README.md b/README.md index b060e1e..b82a1c5 100644 --- a/README.md +++ b/README.md @@ -10,13 +10,13 @@ The project is build over Platformio (http://platformio.org/frameworks) but you ## How it works A 65C02S (modern version of the original 6502) is wired on a breadboard. The 6502 is a very simple kind of CPU in terms of I/O and the modern version allow us to suspend the clock at any time in LOW / HIGH state. -There are 16 Address Pins (A0-A15) each mapping a bit (HIGH/LOW) of an address word. This is how 6502 tell us what address he want to read or write to (RAM/ROM, IO dedicated address spaces). The state of this pins may change at every clock cycle. +There are 16 Address Pins (A0-A15) each mapping a bit (HIGH/LOW) of an address word. This is how 6502 tell us which address he want to read or write to (RAM/ROM, IO dedicated address spaces). The state of this pins may change at every clock cycle. Other 8 pins will carry or expect the 1 Byte data to be stored or read to / from the address above. The CPU tell the external world if the data is in read or write state via R/W pin (HIGH=Expect data IN, LOW=Send data OUT). -This is it. This is all you need to interact with a 6502. The CPU expect a clock signal (HIGH/LOW) on pin 37 (PHI2). The modern version of 6502 is able to suspend any activity for an unlimited period of time during a clock cycle, both in LOW or HIGH state (was a little bit more hard with the original CPU). This make a perfect fit to let us drive the CPU via something different from a crystal, in our case, an Arduino, debug any single clock cycle and keep things in sync. +That's it. This is all you need to interact with a 6502. The CPU expect a clock signal (HIGH/LOW) on pin 37 (PHI2). The modern version of 6502 is able to suspend any activity for an unlimited period of time during a clock cycle, both in LOW or HIGH state (was a little bit more hard with the original CPU). This make a perfect fit to let us drive the CPU via something different from a crystal, in our case, an Arduino, debug any single clock cycle and keep things in sync. Knowing the address space where the Apple 1 was mapping the different IO (Ram / ROM / KEYB / DSP), we can simulate the external interfaces (in fact a PIA 6821) and send back & forth as needed the related data via 6502 data bus. That's it. @@ -53,8 +53,11 @@ The WOZ monitor asm source and the original apple 1 operation manual are two ver +--------------+ | GND + CLOCK_DELAY: A0 - you should connect a potentiometer to A0, this will let you manually sed the clock delay of the 6502. + Note: You may want to put a 100Uf capacitor near the 3.3v & GND lines too. + ## Serial client recommended settings: You should be able to use the standard Serial Monitor in the Arduino IDE or or Platformio (Atom) or any other basic serial client. diff --git a/src/main.cpp b/src/main.cpp index 8a4b009..9b18dd8 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,14 +4,16 @@ #define CHECK_BIT(var,pos) ((var) & (1<<(pos))) +// General Control settings const int SERIAL_SPEED = 115200; // Arduino Serial Speed - -const int CLOCK_PIN = 52; // TO 6502 CLOCK -const int RW_PIN = 53; // TO 6502 R/W -const int CLOCK_DELAY = 3; // HIGH / LOW CLOCK STATE DELAY (You can slow down it as much as you want) +const int CLOCK_DELAY_PIN = A0; // Clock delay PIN (potentiometer) +int CLOCK_DELAY = 5; // HIGH / LOW CLOCK STATE DELAY (You can slow down it as much as you want) const char SERIAL_BS = 0x08; +// 6502 to Arduino Pin Mapping +const int CLOCK_PIN = 52; // TO 6502 CLOCK +const int RW_PIN = 53; // TO 6502 R/W const int ADDRESS_PINS[] = {44,45,2,3,4,5,6,7,8,9,10,11,12,13,46,47}; // TO ADDRESS PIN 1-15 6502 const int DATA_PINS[] = {33, 34, 35, 36, 37,38, 39, 40}; // TO DATA BUS PIN 0-7 6502 @@ -49,26 +51,33 @@ const unsigned char BS = 0xDF; // Backspace key, arrow left key (B7 High) const unsigned char CR = 0x8D; // Carriage Return (B7 High) const unsigned char ESC = 0x9B; // ESC key (B7 High) +// 6502 States buffer unsigned int address; // Current address (from 6502) unsigned char bus_data; // Data Bus value (from 6502) int rw_state; // Current R/W state (from 6502) -unsigned int pre_address; // Current address (from 6502) -unsigned char pre_bus_data; // Data Bus value (from 6502) -int pre_rw_state; // Current R/W state (from 6502) +// 6502 previous States buffer +// We use them to optimize the performance a bit +unsigned int pre_address; // Previous address (from 6502) +unsigned char pre_bus_data; // Previous Bus value (from 6502) +int pre_rw_state; // Previous R/W state (from 6502) + +// Set Arduino Address connected PINS as INPUT void setupAddressPins() { for (int i = 0; i < 16; ++i) { pinMode(ADDRESS_PINS[i], INPUT); } } +// Set Arduino Bus conneced pins mode as IN or OUT void setBusMode(int mode) { for (int i = 0; i < 8; ++i) { pinMode(DATA_PINS[i], mode); } } +// Read 6502 Address PINS and store the WORD in our address var void readAddress() { address = 0; for (int i = 0; i < 16; ++i) @@ -78,6 +87,7 @@ void readAddress() { } } +// Read 6502 Data PINS and store the BYTE in our bus_data var void readData() { bus_data = 0; for (int i = 0; i < 8; ++i) @@ -87,6 +97,7 @@ void readData() { } } +// Read RW_PIN state and set the busMode (aruduino related PINS) to OUTPUT or INPUT void handleRWState() { int tmp_rw_state=digitalRead(RW_PIN); @@ -255,6 +266,14 @@ void loadPROG() { void setup() { pinMode(CLOCK_PIN, OUTPUT); pinMode(RW_PIN, INPUT); + pinMode(RW_PIN, INPUT); + + // You can remove the PIN input here and just set CLOCK_DELAY as const + // Remove also the analogRead on CLOCK_DELAY_PIN in step() below. + pinMode(CLOCK_DELAY_PIN, INPUT); + CLOCK_DELAY=analogRead(CLOCK_DELAY_PIN); + // End of remove + setupAddressPins(); setBusMode(OUTPUT); @@ -273,6 +292,8 @@ void setup() { Serial.print("ERAM: "); Serial.print(sizeof(RAM_BANK_2)); Serial.println(" BYTE"); + Serial.print("CLOCK DELAY: "); + Serial.println(CLOCK_DELAY); loadBASIC(); loadPROG(); @@ -294,17 +315,25 @@ void handleClock() { } void handleBusRW() { - // READ OR WRITE TO BUS? + + // If nothing changed from the last cycle, we don't need to upadte anything if (pre_address != address || pre_rw_state != rw_state) { + // READ OR WRITE TO BUS? rw_state ? writeToDataBus() : readFromDataBus(); pre_address = address; pre_rw_state = rw_state; } } -void loop () { +void step() { + + CLOCK_DELAY=analogRead(CLOCK_DELAY_PIN); // Can be removed, see setup() handleClock(); readAddress(); handleBusRW(); handleKeyboard(); } + +void loop () { + step(); +}