#
#
# Programmer for Isetta TTL cpu
#

version = "251227"

#
# 21-3-2024 changed for Isetta
#
# 17-4-2025 renamed to isetta_rpi
#
# for programming parallel microcode flash with a RPi
# and for debugging
#
#
# Flash type: SST39SF010A or SST39SF020A
#
# needs external level conversion
#
# run with: python3 isetta_rpi (on Raspberry Pi)
#
#
# 20240321 start changes for Isetta
# 20240331 BU2 can read flash ID
# 20240331 BU3 can program flash
# 20240401 BU5 changed CLK polarity (and circuit, diode/cap now)
# 20240414 BU6 All-test function, programmer, single step
# 20240419 Milestone...  runs Apple 1 Basic on Isetta !
# 20240421 BU9
# 20240425 BU10 Downloading to Isetta working (uncompressed)
# later    Downloading (with F command) also working compressed

# 20240505 BU11 Downloading ASCII file also working (dl_type N), will
#             need 0D or 0A at end of lines, will not transfer 00 or FF
#
# 20240531 BU12 This version will work with the milestone, video + ps/2 keyboard !
#
# 20241027 current version saved as Isetta for ISA2409
#
# 20241027 Start adaption for ISA2442 pcb
#
# 20250106 Added some recordtypes for IntelHex download
#
# 20250417 renamed to isetta_rpi



import RPi.GPIO as GPIO
GPIO.setmode(GPIO.BCM)

from time import sleep

from datetime import datetime  # 240509

# import pytz  # python timezones
#from pytz import timezone

import re  # for regular expression

import sys  # 21-4-2025  for exit

# GPIO names

CE = 17  # enable the flash chip(s) when low (ROE/)
WE = 10  # enable write to flash when high (was low) (not PGM/)

CLK = 11 # active clock pulse when high (not CLK_EXT) 1-4 changed to active low
ENA = 16 # disable Isetta clock when high (was low) (not CLK_EXT_EN/)

KB_CLK = 27  # output, inverted, on ISA2409 goes to GP_IN2 but via 
             # modification also to KB_CK (U42-10)
KB_DATA = 2  # output, via modification on PROG2409 and ISA2409, via diode to U43-13


#EXEC = 21  # exec when low, fetch if high  (21 was OE)
#CHARCLK = 11 # CLK coming from Isetta, for Tx-Rx characters
#CHARDATA = 13 # bi-directional data for Tx-Rx

IS_ON = 18 # input, high when Isetta is connected and has power

#### Data from/to Isetta ####

REG_WR = 7  # output, when low writes from RPi to the selected HCT574 register
REG_OE = 12 # output, when high, enables the outputs of the three HCT574 (U1, U2, U3)

REG_A0 = 8
REG_A1 = 13
REG_A2 = 9

# problem, when A0, A1 both 1, writing to a HCT574 will also enable 
# either RD4 or RD5 on the RPi bus !!
# So need a modification:  (on the PROG2409 pcb only)
# Cut the trace to pin 5 of U7 (74HC138)
# Then connect pin 5 of U7 to pin 2 of U6 (REG_OE 74HCT139)



# A2  A1  A0
#
#            *** data from RPi to Isetta ***
#     0   0  none selected
#     0   1  REG_WR writes from RPi to HCT574 U1 (highest 8 bits MIR16-MIR23)
#     1   0  REG_WR writes from RPi to HCT574 U2 (middle 8 bits MIR8-MIR15) 
#     1   1  REG_WR writes from RPI to HCT574 U3 (lowest 8 bits MIR0-MIR7)
#
#            *** data from Isetta to RPi ***
# 1   0   0  Put highest 8 bits MIR16-MIR23 on RPi bus when REG_OE is low
# 1   0   1  Put middle  8 bits MIR8 -MIR15 on RPi bus when REG_OE is low
# 1   1   0  Put lowest  8 bits MIR0 -MIR7  on RPi bus when REG_OE is low
#
# 1   1   1  Put Isetta databus on RPi bus when REG_OE is low
# 0   1   1  Put several signals on RPi bus:  (when REG_OE is low)
#              bit0 FLAG_F
#              bit1 GP_OUT1
#              bit2 SPI_CLK
#              bit3 CLK1


# values to be used with select_reg:
WR_HIGH = 1
WR_MIDDLE = 2
WR_LOW = 3
RD_HIGH = 4
RD_MIDDLE = 5
RD_LOW = 6
RD_DATA = 7
RD_SIGNALS = 3


AD0 = 19
AD1 = 20
AD2 = 21
AD3 = 22
AD4 = 23
AD5 = 24
AD6 = 25
AD7 = 14  # was 26, but that was connected to the wrong pin

# end gpio names

running=1
page=0x0000
sector=0x000
filename=""
fileinfo="";

delay = 0.000005  # delay after setting signals 5 uS
#delay = 0.000001  # delay after setting signals 1 uS

def set_inputs():  #set the RPi bus to inputs
  GPIO.setup(AD0 , GPIO.IN)
  GPIO.setup(AD1 , GPIO.IN)
  GPIO.setup(AD2 , GPIO.IN)
  GPIO.setup(AD3 , GPIO.IN)
  GPIO.setup(AD4 , GPIO.IN)
  GPIO.setup(AD5 , GPIO.IN)
  GPIO.setup(AD6 , GPIO.IN)
  GPIO.setup(AD7 , GPIO.IN)
  sleep(delay)


def init_gpio():
  set_inputs()
  GPIO.setup(WE, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(CLK, GPIO.OUT, initial = GPIO.HIGH) # ch. 1-4
  GPIO.setup(ENA, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(CE, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(REG_WR, GPIO.OUT, initial = GPIO.HIGH)
  GPIO.setup(REG_OE, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(REG_A0, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(REG_A1, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(REG_A2, GPIO.OUT, initial = GPIO.LOW)
  GPIO.setup(IS_ON , GPIO.IN)
  # for console function:
  GPIO.setup(KB_CLK, GPIO.OUT, initial = GPIO.LOW)  # inverted clk from RPi to Isetta
  GPIO.setup(KB_DATA,GPIO.OUT, initial = GPIO.HIGH) # KB data from RPi to Isetta


def idle():
  set_inputs()
  GPIO.output(WE, GPIO.LOW)
  GPIO.output(CLK,GPIO.HIGH)  # ch. 1-4
  GPIO.output(ENA,GPIO.LOW)
  GPIO.output(CE, GPIO.LOW)
  GPIO.output(REG_WR, GPIO.HIGH)
  GPIO.output(REG_OE, GPIO.LOW)



def select_reg(r):
  GPIO.output(REG_A0, r & 0x01)
  GPIO.output(REG_A1, r & 0x02)
  GPIO.output(REG_A2, r & 0x04)


def stopclock():  
  GPIO.output(ENA, GPIO.HIGH)  # disable clock
  GPIO.output(CLK, GPIO.LOW)  # clock inactive (the real clock is inverted)


def clockpulse():   # 1-4-2024 changed to active low
  sleep(delay) 
  GPIO.output(CLK, GPIO.LOW)  # clock active
  sleep(delay)       
  GPIO.output(CLK, GPIO.HIGH)  # clock inactive
  sleep(delay) 

def out_databit(data,bitnr,ioname):
  GPIO.setup(ioname, GPIO.OUT)
  if (data & (0x01<<bitnr)):
    GPIO.output(ioname,GPIO.HIGH)
  else:
    GPIO.output(ioname,GPIO.LOW)

def in_databit(prev,bitnr,ioname):
  if (GPIO.input(ioname) == 1):
     return prev + (0x01<<bitnr)
  else:
     return prev

# read the 8-bit databus from Isetta

def in_data():
  set_inputs()             # set RPI bus to input
  GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus, also
                           # eables one of the inputs
  select_reg(RD_DATA)  # select U11, 74LVC244A, on programmer
  sleep(delay)
  v = in_databit(0, 0, AD0)
  v = in_databit(v, 1, AD1)
  v = in_databit(v, 2, AD2)
  v = in_databit(v, 3, AD3)
  v = in_databit(v, 4, AD4)
  v = in_databit(v, 5, AD5)
  v = in_databit(v, 6, AD6)
  v = in_databit(v, 7, AD7)
  GPIO.output(CE,GPIO.HIGH) # disable output of flash chip (might have been enabled)
  GPIO.output(REG_OE,GPIO.HIGH) # HCT574 driving microcode bus again

  return v

def in_signals():
  set_inputs()             # set RPI bus to input
  GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus, also
                           # eables one of the inputs
  select_reg(RD_SIGNALS)  # select U5, 74LVC244A, on programmer
  sleep(delay)
  v = in_databit(0, 0, AD0)
  v = in_databit(v, 1, AD1)
  v = in_databit(v, 2, AD2)
  v = in_databit(v, 3, AD3)
  v = in_databit(v, 4, AD4)
  v = in_databit(v, 5, AD5)
  v = in_databit(v, 6, AD6)
  v = in_databit(v, 7, AD7)
  return v


# read 24 bit data from the Isetta microcode flash chip and return it as function result

def in_word():
  set_inputs()             # set RPI bus to input
  GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus
  sleep(delay)
  GPIO.output(CE,GPIO.LOW) # enable output of flash chip 
  select_reg(RD_LOW)  # select U10 on programmer
  sleep(delay)
  v = in_databit(0, 0, AD0)
  v = in_databit(v, 1, AD1)
  v = in_databit(v, 2, AD2)
  v = in_databit(v, 3, AD3)
  v = in_databit(v, 4, AD4)
  v = in_databit(v, 5, AD5)
  v = in_databit(v, 6, AD6)
  v = in_databit(v, 7, AD7)
  select_reg(RD_MIDDLE)  # select U9
  sleep(delay)
  v = in_databit(v, 8, AD0)
  v = in_databit(v, 9, AD1)
  v = in_databit(v, 10, AD2)
  v = in_databit(v, 11, AD3)
  v = in_databit(v, 12, AD4)
  v = in_databit(v, 13, AD5)
  v = in_databit(v, 14, AD6)
  v = in_databit(v, 15, AD7)
  select_reg(RD_HIGH)  # select U8
  sleep(delay)
  v = in_databit(v, 16, AD0)
  v = in_databit(v, 17, AD1)
  v = in_databit(v, 18, AD2)
  v = in_databit(v, 19, AD3)
  v = in_databit(v, 20, AD4)
  v = in_databit(v, 21, AD5)
  v = in_databit(v, 22, AD6)
  v = in_databit(v, 23, AD7)
  return v

# check if the word, that was placed on microcode bus, can be
# correctly read back
# However, it doesnt work. Can not read the bus while the 574's are output-enabled.

def check_word(value):
  set_inputs()             # set RPI bus to input
  #GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus
  # HCT574 keeps driving bus
  sleep(delay)
  #GPIO.output(CE,GPIO.LOW) # enable output of flash chip 
  select_reg(RD_LOW)  # select U10 on programmer
  sleep(delay)
  v = in_databit(0, 0, AD0)
  v = in_databit(v, 1, AD1)
  v = in_databit(v, 2, AD2)
  v = in_databit(v, 3, AD3)
  v = in_databit(v, 4, AD4)
  v = in_databit(v, 5, AD5)
  v = in_databit(v, 6, AD6)
  v = in_databit(v, 7, AD7)
  select_reg(RD_MIDDLE)  # select U9
  sleep(delay)
  v = in_databit(v, 8, AD0)
  v = in_databit(v, 9, AD1)
  v = in_databit(v, 10, AD2)
  v = in_databit(v, 11, AD3)
  v = in_databit(v, 12, AD4)
  v = in_databit(v, 13, AD5)
  v = in_databit(v, 14, AD6)
  v = in_databit(v, 15, AD7)
  select_reg(RD_HIGH)  # select U8
  sleep(delay)
  v = in_databit(v, 16, AD0)
  v = in_databit(v, 17, AD1)
  v = in_databit(v, 18, AD2)
  v = in_databit(v, 19, AD3)
  v = in_databit(v, 20, AD4)
  v = in_databit(v, 21, AD5)
  v = in_databit(v, 22, AD6)
  v = in_databit(v, 23, AD7)
  if (v != value):
    print("BUS ERROR data=",hexfmt(v)," but written was: ",hexfmt(value) )
  return



# write 24 bit data from the RPi to the Isetta microcode bus


def out_word(data):
  GPIO.output(CE,GPIO.HIGH) # disable flash output before putting info on bus
  sleep(delay)
  GPIO.output(REG_OE,GPIO.HIGH) # HCT574 now driving microcode bus. 
                                # De-activates the buffers from Isetta to RPi
  out_databit(data,0,AD0)
  out_databit(data,1,AD1)
  out_databit(data,2,AD2)
  out_databit(data,3,AD3)
  out_databit(data,4,AD4)
  out_databit(data,5,AD5)
  out_databit(data,6,AD6)
  out_databit(data,7,AD7)  
 
  select_reg(WR_LOW)  # select U3 on programmer
  sleep(delay)
  GPIO.output(REG_WR,GPIO.LOW) # low pulse writes 8 bit to U3
  sleep(delay)
  GPIO.output(REG_WR,GPIO.HIGH) # end write pulse
  sleep(delay)
  out_databit(data,8,AD0)
  out_databit(data,9,AD1)
  out_databit(data,10,AD2)
  out_databit(data,11,AD3)
  out_databit(data,12,AD4)
  out_databit(data,13,AD5)
  out_databit(data,14,AD6)
  out_databit(data,15,AD7) 

  select_reg(WR_MIDDLE)  # select U2 on programmer
  sleep(delay)
  GPIO.output(REG_WR,GPIO.LOW) # low pulse writes 8 bit to U2
  sleep(delay)
  GPIO.output(REG_WR,GPIO.HIGH) # end write pulse
  sleep(delay)
  out_databit(data,16,AD0)
  out_databit(data,17,AD1)
  out_databit(data,18,AD2)
  out_databit(data,19,AD3)
  out_databit(data,20,AD4)
  out_databit(data,21,AD5)
  out_databit(data,22,AD6)
  out_databit(data,23,AD7)  

  select_reg(WR_HIGH)  # select U1 on programmer
  sleep(delay)
  GPIO.output(REG_WR,GPIO.LOW) # low pulse writes 8 bit to U1
  sleep(delay)
  GPIO.output(REG_WR,GPIO.HIGH) # end write pulse
  sleep(delay)
  #check_word(data)  # check if the 24 bits on the bus are correct. doesnt work.
  # it is up to the caller of the "out_word" function to write the 24 bit data
  # to either the flash or the microcode MIR register

#############################################################

# getpat(00x0x00x) will return 0-7 to get that pattern from ident table.

def getpat(pat):
  n = 0
  if (pat & 0x01):
    n += 1  # ctl bit REG0
  if (pat & 0x08):
    n += 2  # ctl bit REG1
  if (pat & 0x20):
    n += 4  # ctl bit REG2
  return n

# get_ir: prepare the IR value and put it in register 0

def get_ir(val):
  pat = getpat( (val>>1) & 0x29 )  # have to load this, shifted left

  out_word(0x0B4200 +pat)  #  A <- ASL(value(pat)) # 2-11-2024 bank 0
  clockpulse()
  #pause(" 00x0 x00x on databus, will be shifted left")

  pat = getpat( val & 0x29 )  # have to add this
  if (pat !=0):

    out_word(0x0D4280 +pat)  #  A <- ADD(A,value(pat)) # 2-11-2024 bank 0
    clockpulse()
    #pause(" 00x0 x00x on databus, will be added to prev shifted value")

  # only x000 0x00 still to do, so values 4, 128, 132
  val = val & 0x84
 
  if (val==4): 
     out_word(0x0D42B1)  # add 4 to A  2-11-2024 bank3 now
     clockpulse()
  if (val==128): 
    out_word(0x0D42B2)  # add 128 to A
    clockpulse()
  if (val==132): 
    out_word(0x0D42B3)  # add 132 to A
    clockpulse()
  #pause(" x000 0x00 on databus, will be added to prev shifted value")

  out_word(0x0032B0)  # write A to memory-register 0  2-11-2024 use bank 3
  clockpulse()


# reg 201 used for value 4
# reg 202 used for value 128
# reg 203 used for value 132 (128+4)
# reg 204 used for value 0x55
# reg 205 used for value 0xaa
# 2-11-2024 now reg 231 - 235

def set_address(addr):  
  GPIO.output(CE,GPIO.HIGH) # disable flash output 
  GPIO.output(ENA,GPIO.HIGH)  # disable Isetta clock  24-3 ch. pol. Isetta

  if (addr & 0x01):
    out_word(0x200800)  # flag F ON
  else:
    out_word(0x000800)  # flag F OFF
  clockpulse()  # write F on/off instruction

  # address: P PPPIIIII IIICCCCF

  new_ir = (addr >> 5) & 0x00FF   # IIIIIIII bits (instruction)
  new_count = (addr >> 1) & 0x0F  # CCCC  bits (count)
  new_page  = (addr >>13) & 0x0F  # PPPP  bits (page)

  # memory-register 0 has the new IIIIIIII.

  # now prepare the LD_IR instruction that will write the microcode flash address

  # instruction: 000P PPP8 0110 0010 0000 0000 
  # last part is mem addr of T: xxx200
  # the '8' will set the highest count-bit (count = bit3210)
  # The count bits 210 can only be changed by giving clockpulses.

  new_ld_ir = (new_page << 17)

  if (new_count >= 8):
    new_ld_ir += 0x010000  # set the '8' bit
    new_count -=8;

   
  if (new_ir == 0x55):
    new_ld_ir += 0x006234  # 6=dest_ir, 204=mem_addr (has 0x55 value) 2-11-2024
    out_word(new_ld_ir)  # write to microcode address
    clockpulse()

  else:
    if (new_ir == 0xaa): 
      new_ld_ir += 0x006235  # 6=dest_ir, 205=mem_addr (has 0xaa value) 2-11-2024
      out_word(new_ld_ir)  # write to microcode address
      clockpulse()    
    else:
      new_ld_ir += 0x006230  # 6=dest_ir, 200=mem_addr  2-11-2024 bank 3
      # the instruction, new_ld_ir, refers to register 230. But that is not filled yet.
      # The get_ir() will fill the register 230.
      get_ir(new_ir)

      out_word(new_ld_ir)  # write to microcode address
      clockpulse()
      #pause("IR should be filled now ? NO, its on the databus")
      check = in_data()  # read the new IR value from the bus
      #ir_val = (addr >> 5) & 0x00FF  # what it should be
      if ( new_ir != check ):
        print("ADDR ERROR at ",hexfmt(addr)," data=",hexfmt(check)," but should be: ",hexfmt(new_ir) )
        print("Retry")
        get_ir(new_ir)
        out_word(new_ld_ir)  # write to microcode address
        clockpulse()
        check = in_data()  # read the new IR value from the bus to check again
        if ( new_ir != check ):
          print("ADDR ERROR at retry, data=",hexfmt(check)," but should be: ",hexfmt(new_ir) )
        else:
          print ("Retry ok"); 

  out_word(0x014000)  # load A from (pc), used as NOP
  clockpulse()  # one more pulse (NOP) to get it into IR

  # now give some clock pulses to get the lower 3 bits correct

  while (new_count !=0):
    clockpulse()
    new_count -= 1

# now, the address wil be on the address bus of the flash chips.

################################################################

def pause(prompt):
  char = input("Pause: " + prompt)

  
def read(addr):		# Read a word from the Flash
  set_address(addr)
  set_inputs()             # set RPI bus to input
  # GPIO.output(CE,GPIO.LOW) # enable flash chip  (done in in_word)

  sleep(delay)
  v = in_word()   # read data

  GPIO.output(CE,GPIO.HIGH) # disable flash chip 

  sleep(delay) 
  return v
  

def write(addr,data):	# Write a word to the Flash
  set_address(addr)
  out_word(data)
  #pause("addr and data written")
  #char = input("ADDR and DATA written, line 585 >>") # DEBUG 2-11-2024
  GPIO.output(WE, GPIO.HIGH)  # start write pulse  25-3 changed polarity (Isetta)
  sleep(delay)   
  GPIO.output(WE, GPIO.LOW)  # stop write pulse
  sleep(0.0002) 	    # use fixed programming time, 250417 0.0002 was 0.0001
#  idle()

 

def display_addr(addr):
  print("addr "+hex(addr)+" : "+ hex(read(addr)))
  

def clockcommand():  # Kobold new
  set_inputs()             # set RPI bus to input
  GPIO.output(CLK, GPIO.LOW)  # clock inactive
  sleep(0.00001) 
  GPIO.output(CE,GPIO.LOW) # enable output from Kobold or memory 
  GPIO.output(CLK, GPIO.HIGH)  # clock active (real clock is inverted)
  sleep(0.00001)             # 10uS is long enough
  v = in_word()   # read data
  print("Data on bus : ",hexfmt(v) );
#  GPIO.output(CLK, GPIO.LOW)  # clock inactive done at next clock pulse
  sleep(0.00001) 


def unlock(code):
  write(0x5555,0xAAAAAA)  # 1st bus cycle
  write(0x2AAA,0x555555)  # 2nd bus cycle
  write(0x5555, code)   # 3rd cycle, depends on action

# byte_program will program three bytes data to three 8 bit flash chips

def byte_program(addr,data):
  unlock(0xa0a0a0)   # Byte-Program command
  write(addr,data)

def erase_all(): # erase microcode chips
  unlock(0x808080)   # sector erase, first 3 cycles
  write(0x5555,0xAAAAAA)  # bus cycle 4
  write(0x2AAA,0x555555)  # bus cycle 5
  write(0x5555,0x101010)  #  17-7-2020 erase whole chips


def hexfmt(nr):  # convert hex to 4 char hex string
  #return ("000"+hex(nr)[2:])[-4:]
  return hex(nr)  # todo: make 6-char string


def page_display():  # command r  changed for kobold words
  row = 0
  col= 0
  while (row<16):
    print ( hexfmt(page+row*16)+"   ",end="")  # print without NL
    col=0
    while (col<8):      
      print ( hexfmt(read(page+row*8+col))+" ",end="")
      col=col+1  # was 2 !!
    print (" ")  # force NL
    row=row+1

def show_id():
  # read chip id
  print ("Read ID, must be bfbfbf followed by b5b5b5 :") 
  unlock(0x909090)   # software ID entry
  print("Manufacturer "+hexfmt(read(0)) )  # should be BF
  print("Device       "+hexfmt(read(1)) )  # display Device ID, should be B5
  unlock(0xf0f0f0)   # software ID exit
  date = read(30)    # location 30 contains the date of the microcode
  print("Microcode date in flash: ",hexfmt(date))


microcodefilename = 0;

test_output = 1

# programming and verifying from file. All numbers in hex.

# for Isetta, we use the same data format as for the Logisim simulation.

# 'dofile' is used for programming and verifying the 3 flash memories.

def dofile(what):  
  global test_output
  test_output=0
  AutomaticTest()   # test the HW function, will also initialize some registers that
                    # are needed for programming/verifying.
  global microcodefilename
  try:
    if (what=="v"):
      print("Verification of Isetta microcode")
    else:
      print("Programming of Isetta microcode")

    #f = open("microcode bin 250409A.txt")
    if (microcodefilename ==0):
      microcodefilename = input("microcode filename: ")

    f = open(microcodefilename)	

    addr = 0
    errcnt=0
    print("page 0  Reset / Z80_ED")
    print("page 2  6502")
    print("page 4  Z80")
    print("page 6  Z80_IX / IN")
    print("page 8  Z80_CB")
    print("page 10 Z80_IY / OUT")
    print("page 12 DATA")
    print("page 14 DATA")
    print("page 16 Spectrum_video/blitter_copy")
    print("page 18 Copycnv")
    print("page 20 HIRES / BLITTER")
    print("page 22 PSG / RTC")
    print("page 24 DATA")
 	
    # first line has info, skip it:
    dummy = f.readline()
    # every line has a number of data values. There are no addresses.

    print("Enter the pages, separate with spaces. A = all pages.")
    pages = input("P:")
    thispage = 0
    
    if (pages[0].lower() == 'a'):
      pages = "0 2 4 6 8 10 12 14 20"  # all pages
    pages = pages+chr(0x0D)
    print("pages: ",pages)

    while pages[0].isdigit():  # digit present ?
      thispage = 10*thispage + ord(pages[0]) - ord("0")
      pages = pages[1:]           # remove char from string
    print("first page for program/verify: ",thispage)
    while (pages[0]==' '):
      pages = pages[1:]  # skip spaces
    skip = 1;

    while True:

      line = f.readline()
      if not line:
        break
      #print(line)  # for testing
      values = line.split(' ')

      for i in values:
        # handle each value i
        #print(i) 
        data = int(i,16)  # convert hex string to number (base 16)
        #print (addr,':',hexfmt(data))
        if (addr==30):
          print("Microcode date: ",i)
        #check if addr is first one of the wanted page
        if (addr == (thispage << 12)):
          if (what=="v"):
            print("Start verifying page ",thispage)
          else:
            print("Start programming page ",thispage)
          skip=0
          if (what=="p"):
            # erase two 4K flash pages
            unlock(0x808080)   # sector erase, first 3 cycles
            write(0x5555,0xAAAAAA)  # bus cycle 4
            write(0x2AAA,0x555555)  # bus cycle 5
            sector = thispage << 12
            write(sector,0x303030)  # bus cycle 6 has sector number
            sleep(0.050)     # sector erase time 18mS typ.
            unlock(0x808080)   # sector erase, first 3 cycles
            write(0x5555,0xAAAAAA)  # bus cycle 4
            write(0x2AAA,0x555555)  # bus cycle 5
            sector = ((thispage+1) << 12) 
            write(sector,0x303030)  # bus cycle 6 has sector number
            sleep(0.050)
            # 1-12-2025 retry the erase action
            unlock(0x808080)   # sector erase, first 3 cycles
            write(0x5555,0xAAAAAA)  # bus cycle 4
            write(0x2AAA,0x555555)  # bus cycle 5
            sector = thispage << 12
            write(sector,0x303030)  # bus cycle 6 has sector number
            sleep(0.050)     # sector erase time 18mS typ.
            unlock(0x808080)   # sector erase, first 3 cycles
            write(0x5555,0xAAAAAA)  # bus cycle 4
            write(0x2AAA,0x555555)  # bus cycle 5
            sector = ((thispage+1) << 12) 
            write(sector,0x303030)  # bus cycle 6 has sector number
            sleep(0.050)

        if (skip==1):
          data=0

        # check if addr is the last one of the wanted page
        if (addr == (thispage << 12)+0x1FFF):
          skip=1
          print("End programming/verifying page ",thispage)
          thispage=0
          if not pages[0].isdigit():
            thispage =99 # 
          while pages[0].isdigit():  # digit present ?
            thispage = 10*thispage + ord(pages[0]) - ord("0")
            pages = pages[1:]           # remove char from string
          print("next page for program/verify (99=end): ",thispage)
          while (pages[0]==' '):
            pages = pages[1:]  # skip spaces

        # go program/verify the addr if data != 0
        if (data !=0):   # locations that contain 0 will not be programmed/verified
          if (what=="p"):
            byte_program(addr,data)
            if (addr < 20):
              print("Location "+hexfmt(addr)+" set to "+hexfmt(data) )
            if (addr==20):
              print("Stop reporting.")
            d = in_word()  # verify
            if (d != data):
              print("PGM ERROR, at "+hexfmt(addr)+" wrote "+hexfmt(data)+" but read "+hexfmt(d) )
              print("Retry")
              byte_program(addr,data)
              d = in_word()  # verify
              if (d != data):
                print("PGM ERROR, at "+hexfmt(addr)+" wrote "+hexfmt(data)+" but read "+hexfmt(d) )
                errcnt += 1
              else:
                print("Retry ok")

          if (what=="v"):
            d = read(addr)
            if (d !=data):
              print("Verify error, at "+hexfmt(addr)+" expect "+hexfmt(data)+" but found "+hexfmt(d) )
              print("Retry")
              d = read(addr)
              if (d != data):
                print("Verify error, at "+hexfmt(addr)+" expect "+hexfmt(data)+" but found "+hexfmt(d) )
                errcnt += 1
              else:
                print("Retry ok")

        if ((addr &0xFF) == 0xFF):
          print(  hexfmt(addr & 0xFFF00),"-",hexfmt(addr))
        addr +=1
        # end of for loop
      #if (addr > 0x4000):
      #  break  # temp limit output
      if (errcnt > 20):
        print("More than 20 errors, stop.")
        break  # temp limit output
      # end of while loop

    f.close()
    if (what=="v"):
      print("Verify errors: ",errcnt)
    else:
      print("Programming errors: ",errcnt)
  except FileNotFoundError:
    print("ERROR FILE NOT FOUND")
    microcodefilename =0
  else:
    print("Done")  



def file_info():
  try:
    f = open(filename)
    txt = next(f)
    f.close()
  except FileNotFoundError:
    txt = "ERROR, File not found"
  return txt

# commands Instruction, Mem_read and Write

def mem_read(inp):		# input: M xxxx  // provide xxxx as instruction operand
  if (GPIO.input(EXEC) == 0):
    nr = int(inp[1:],16) 
    out_word(nr)
    #GPIO.output(CLK, GPIO.HIGH)  # clock active
    clockpulse()
    print("provide "+inp+" in read action")
  else:
    print("Can not read in FETCH phase")

def instruction(inp):		# input: I xxxx // exec instr. xxxx
  if (GPIO.input(EXEC) == 1):
    nr = int(inp[1:],16) 
    out_word(nr)
    #GPIO.output(CLK, GPIO.HIGH)  # clock active
    clockpulse()
    print("provide "+inp+" in instruction")
  else:
    print("Can not provide instruction in EXEC phase")

def mem_write():		# input: W  // CPU writes word, displayed on screen
  set_inputs() 
  GPIO.output(CE,GPIO.LOW)   # enable kobold cpu output
  if (GPIO.input(EXEC) == 0):
    GPIO.output(CLK, GPIO.HIGH)  # clock active
    sleep(0.00001)        # 10uS is long enough
    res = in_word()
    GPIO.output(CLK, GPIO.LOW)  # clock inactive
    print("Kobold wrote: "+hexfmt(res))
  else:
    print("Can not write in FETCH phase")

# 21-1-2020 commands that exec from Flash instead of manual

def new_mem_read(inp):		# input: N  // provide operand from memory
  if (GPIO.input(EXEC) == 0):
    set_inputs() 
    GPIO.output(CE,GPIO.LOW)   # enable kobold cpu output
    #out_word(nr)
    GPIO.output(CLK, GPIO.HIGH)  # clock active
    sleep(0.00001)  
    res = in_word()
    GPIO.output(CLK, GPIO.LOW)  # clock inactive
    #clockpulse()
    print("Kobold read operand: "+hexfmt(res))
    
  else:
    print("Can not read operand in FETCH phase")

def j_instruction(inp):		# input: J // exec instr. from memory
  if (GPIO.input(EXEC) == 1):
    set_inputs() 
    GPIO.output(CE,GPIO.LOW)   # enable kobold cpu output
    #out_word(nr)
    GPIO.output(CLK, GPIO.HIGH)  # clock active
    sleep(0.00001) 
    res = in_word() 
    GPIO.output(CLK, GPIO.LOW)  # clock inactive
    #clockpulse()
    print("Kobold instruction: "+hexfmt(res))
  else:
    print("Can not do instruction in EXEC phase")


# transmit AND receive a char to/from Isetta:

charsonline = 0
file_state=0

def chartransfer(byte):

  # startbit
  GPIO.output(KB_DATA,GPIO.LOW)   # startbit
  sleep(0.00001)
  GPIO.output(KB_CLK,GPIO.HIGH)   # clk is inverted
  sleep(0.00005)  # 50uS
  GPIO.output(KB_CLK,GPIO.LOW)    # clk is inverted
  sleep(0.00005)  # 50uS
  # send bits one by one
  # PS/2 starts with LSB, but here we start with MSB
  rxbuf = 0
  count = 0
  while (count<9):     # send 8 bits + 1 parity bit (unused)
    if (byte & 0x80):
      GPIO.output(KB_DATA,GPIO.HIGH)     
    else:
      GPIO.output(KB_DATA,GPIO.LOW)
    sleep(0.00001)
    GPIO.output(KB_CLK,GPIO.HIGH)   # clk is inverted
    sleep(0.00002) # 20 uS
    GPIO.output(KB_CLK,GPIO.LOW)    # clk is inverted
    sleep(0.00002) # 20 uS
    byte = (byte <<1) & 0x00ff
    # read bit from Isetta

    rxbuf = (rxbuf << 1) + GPIO.input(AD1)  # get input bit
    # print(rx>>1) # debug
    count = count+1
  # ok the char was sent
  GPIO.output(KB_DATA,GPIO.HIGH)  # set data line back to inactive state
  # 2-5-2024 add stopbit
  GPIO.output(KB_CLK,GPIO.HIGH)   # clk is inverted
  sleep(0.00002) # 20 uS
  GPIO.output(KB_CLK,GPIO.LOW)    # clk is inverted
  sleep(0.00002) # 20 uS

  rxbuf = rxbuf >>1   # remove the paritybit

  return rxbuf  



def printchar(rxbuf):
  global charsonline
  if (rxbuf&0X7F==0x0D):
    print() # newline
    charsonline = 0
  else:
    if (rxbuf != 255):
      rxbuf = rxbuf & 0x7F  # Apple 1 BASIC sends chars with upper bit set, clear it
      #print("[",hexfmt(rxbuf),"]", end = '')  # optionally print in hex 
      print(chr(rxbuf), end = '', flush=True)  # print char use chr(data)    
      charsonline +=1
  if (charsonline >110):
    print()   # wrap to next line
    charsonline=0

dl_file =0  # handle for the file that is downloaded
dl_index = 0
dl_line = ""  # the line to send
force_err = 6  # force err after 6 lines
esc_char = 0

dl_type = " "  # will be N for no compression, D for Intel Hex


# note that the file that is downloaded must have lines (0x0D or 0x0A bytes)

def getbyte():   # get a char from the dl_file
  global dl_index
  global dl_line
  global dl_file
  global file_state
  global force_err
  global esc_char
  global dl_type

  if (esc_char !=0):
    result = esc_char
    #print ("[ esc-char ",chr(result),"]")  # debug
    esc_char = 0
    return result

  if (dl_index >= len(dl_line)):
    if (file_state==4):  # done sending 'not found'
      file_state=0

    if (file_state==3):  # done sending file
      dl_line = dl_file.readline()
      force_err -=1;
      dl_index=0
      if not dl_line:
        print("[end of file]")
        dl_file.close()
        file_state=0
        if (dl_type=='N'):
          return ord("!")  # 5-5-2024 end of file
        if (dl_type=='D'):
          file_state=4  # 10-5-2024 end of file, add "[E"
          #dl_line = "[E"  # ehhh  [ will be escaped
          esc_char= ord("E")
          dl_index=0
          return ord("[")

    result = 255
  else:   
    result = ord(dl_line[dl_index])

    if (result == 10):
      result = 13  # change LF into CR
    #else:
    # if (force_err==0):
    #   result += 1  # force err, to check response
    dl_index += 1

  # Here we can either return the result (an ASII char),
  # or make the system a lot faster by combining two nibbles.

  # return result  # output seems OK (debug print statements) but Isetta doesnt understand it

  #print('(',hexfmt(result),')' ) # 9-1 debug

  if (dl_type == "N"):
    if (result==ord("[") ):  # send [ as "[["
      esc_char = result
      result = ord("[")
    if (result == ord("!")):  # send ! as "[D" ( "!" is used for end of file )
      esc_char= ord("D")
      #print("[ esc D ]")
      result = ord("[") 
    return result   # simply send the char
 
  if (result==255):
    return result
  if (result==13):
    return result
  if (result == ord(":")):
    esc_char = 0
    #print("=");
    return ord("=")  # note that = is sent instead of : to indicate fast mode
  if (result >=ord("A")):
    result = result - 7
  if (result > ord("A")):   # this can happen with lower case a-f
    result = result - 32
  nibble = result - ord("0")  # now have nibble value

  # get next nibble. It will be on the same line, making this easy
  result = ord(dl_line[dl_index])
  #print('{',hexfmt(result),'}' ) # 9-1 debug

  dl_index+=1
  if (result >=ord("A")):
    result = result - 7
  if (result > ord("A")):   # this can happen with lower case a-f
    result = result - 32
  # combine the nibbles
  result = (nibble<<4)   + (result - ord("0"))  # now have nibble value 

  if ((dl_type == "F") and (result == 0x55)):
    # the file was not found. Send '[F' to the file transfer command
    esc_char= ord("F")
    #print("esc")
    return ord("[") 

  # But a few values can not go through the communication channel (0 and 0xFF)
  # so they are escaped
  result = result ^ 0x40  # simple scrambling so 00 and FF wont appear so often
  if (result==ord("[") ):
    esc_char = result
    #print("esc [ ")
    result = ord("[")
  if (result==0):
    esc_char= ord("A")
    #print("esc 0 ")
    result = ord("[")
  if (result==255):
    esc_char= ord("B")
    #print("esc FF")
    result = ord("[")

  #print(hexfmt(result),hexfmt(result ^ 0x40) ) # 9-1 debug
  return result
        


 
def exec_isetta():   # let Isetta run on its own clock, do console I/O (command X)
  global file_state
  global filename
  global dl_file
  global dl_index
  global dl_line
  global dl_type
  global charsonline # 9-2-2025
  filename =""
  idle()
  set_inputs()             # set RPI bus to input
  GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus, also
                           # eables one of the inputs
  select_reg(RD_SIGNALS)  # select U5, 74LVC244A, on programmer
  sleep(delay)

  print("Send command strings to Isetta")
  while (1):
    # read a char from keyboard (requires that it's followed by CR)
    print()   # put the prompt on a new line
    try:  # 21-4-2025 added catching ^C
      line = input(">>")
    except KeyboardInterrupt:
      idle()
      GPIO.cleanup();
      print()
      print(" ^C  end isetta_rpi")
      sys.exit()  # terminate program
    line = chr(255) + line + chr(0x0D)  # 255 provides bit synchronization (if needed)
    charsonline = 0 # 9-2-2025

    count = 0
    while (count < 200):   # stop after 50 times receiving 255   TEMP 100
    #while (count < 100):     # fix for auto switch to PS/2 kb
      if (len(line) > 0):
        byte = ord(line[0])  # first char of string
        line = line[1:]      # remove first char
        count = 0
      else:
        byte=255 

      if (file_state>=3):   # for state 3 and 4
        byte = getbyte()
        # print("[",byte,chr(byte),"]", end = '', flush=True)  # test, also send file to screen
        count = 0

      #if (byte !=255):
      #  print("[",hex(byte),chr(byte),"]", end = '', flush=True) # debug
      rx = chartransfer(byte) # send a byte and receive a byte
      if (chr(rx)=="%"):      # a normal % will be sent as %%. Convert back to %
        if (file_state==0):
          file_state=1
          filename =""
        else:
          if (file_state==1): 
            file_state=0
            printchar(rx)
          else:
            if (file_state==2):   # a filename was entered
              try:
                dl_file = open(filename)
                file_state=3     # state 3, opened file
                dl_index=0       # start reading with char nr 0
                dl_line = "" 
                #dl_file.close()
                #file_state=0     # after closing, state is 0 again
              except FileNotFoundError:
                print("[not found: ",filename,"]")
                # send two types of file not found message:
                # :00000099FF  fitting the regular Intel format
                # 55  -> [F    for the transfer command, that doesnt interpret
                
                dl_line = ":00000099FF55" # 'file not found' recordtype
                dl_index = 0
                dl_type='F'   # dl_type F  for file not found
                file_state=4    # state 4 for sending 'not found' message 
              else:
                print("[file opened]") 
            else:
              if (file_state==3): # receiving '%' while sending file means err occurred.   
                if (dl_type !="N"):
                  print("[error reported]")
                  file_state=0
                  dl_file.close()  
                # else, % should be printed, but that follows because its send as %%
      
      else:
        if (file_state==1):
          # after %, a command follows (D = download, N = no compression  T=time).
          dl_type = chr(rx);
          print("[download mode:",chr(rx),"]")
          file_state=2
          if (dl_type=="T"):
            file_state=4    # will send date&time to Isetta after %T received
            dl_index=0       # start reading with char nr 0
            # recordtype 0x70 used to indicate it is date&time
            # data length 0x08  checksum 00 (not checked)
            dl_line = ":08000070"+do_date_time()+"0000"
            #print('[ dl_line=',dl_line,']') # debug
          else: 
            if ((dl_type!="D") and (dl_type!="N")):
              file_state=0  # must be an error, go out of file transfer state.
        else:
          printchar(rx)
          if (file_state==2):
            filename = filename + chr(rx)  # add to filename

      if (rx != 255):
        count=0

      count += 1







#############################################################

# Isetta singlestep from flash

def Singlestep():
  err=1
  searchlaunch=0
  last_opcode=1234; # 2-11-2024
  iteration =0;
  to_it_end = 0;
  to_in =0;
  opcode=0
  page=0;
  stopclock()
  '''
  while(err==1):
    str = input("Microcode start addr(hex): ")
    try:
      num = int(str,16)
      set_address(num)
      err=0
      out_word(num)
           
    except ValueError:
      print("Not a hex number")
  '''
  # 22-12-2024 start with loading PC from HL
  print("PC will be loaded from the HL register")
  teststep(0x01524D,0,0x00,"read PCL from L"); # read PCL from L
  teststep(0x01524C,0,0x00,"read PCH from H"); # read PCH from H

  # set the 'GO' instruction (opcode 7) in page 0 as microcode start point

  # address: P PPPIIIII IIICCCCF

  #set_address(0x0000E0); # this doesnt work

  teststep(0x1B2202,0,0x00,"load dpl with 7"); # load dpl with (8-1)
  teststep(0x006126,0,0x00,"ld_ir dpl,page0"); # ld_ir (dpl) page 0
  teststep(0xE60A00,0,0x00,"delay"); # delay

  err=0;

  # 22-12-2024 end

  stepcount=0   
  while(err==0):  
    set_inputs()             # set RPI bus to input
    # GPIO.output(CE,GPIO.LOW) # enable flash chip  (done in in_word)
    sleep(delay)
    char=' '
    v = in_word()   # read data
 
    stepcount = stepcount+1
    if ((opcode==1) and (searchlaunch==0)):  # read opcode from databus
      data = in_data()
      if (data==0xdb): # input instruction
        to_in=0
      # 2-11-2024 if same opcode is repeated, display iteration number
      if (data == last_opcode):
        iteration = iteration+1;
        print("-----> opcode ",hexfmt(data),"  iteration ",iteration) 
      else:
        print("-----> opcode ",hexfmt(data))
        iteration = 1
        to_it_end = 0
      last_opcode = data
      # teststep(0x010022,0,0x00,"Read PCL (to T)  -->"); # read PCL
      # teststep(0x0C5200,0,0x00,"Write T to register PCH")
      # teststep(0x010022,0,0x00,"Read PCH (to T)  -->"); # read PCL
      # teststep(0x0C5200,0,0x00,"Write T to register PCH")
      # didnt work, have to set step count back to 0, and even then ???
      GPIO.output(REG_OE,GPIO.LOW) # HCT574 no more driving microcode bus
      sleep(delay)
      GPIO.output(CE,GPIO.LOW) # enable output of flash chip 
      sleep(delay)
      opcode=0
      stepcount=0

    if ((v & 0x007000)==0x006000):
      page = (v & 0x1F0000)>>16
      print("Next instruction: page ", page )
      opcode=1  # display opcode in next cycle

    if (page==12):
      searchlaunch=2
    if ((searchlaunch==2) and (page==0)): 
      # found the launch (after program download)
      searchlaunch=0


    clockpulse()    

    if 1: # (searchlaunch==0):
      data = in_data()
      print("count: ",stepcount," Microcode: "+hexfmt(v)+" Data: "+hexfmt(data))
      if ((to_it_end==0) and (to_in==0)):
        char = input("'Enter'=step (Quit, L:tolaunch E:to_iter_end, I:to_IN): ")

    char = char.lower()
    if (char=='r'):  # set interrupt request 24-12-2024
      teststep(0x3D7202,0,0x00,"irq pulse on"); # set
      teststep(0x1D7202,0,0x00,"irq pulse off"); # reset # this doesnt work !!
    if (char=='q'):
      err=1
    if (char=='l'):
      searchlaunch=1
    if (char=='e'):
      to_it_end=1
    if (char=='i'):
      to_in=1

  print("Quit singlestepping")


#############################################################

# Isetta test programs

# Enter a microcode manually. The code will be executed on Isetta and the
# databus contents will be displayed (except for memory write).

errorcount = 0

def MicrocodeIsetta():
  err=0
  stopclock()
  while(err==0):
    str = input("Hex microcode (Q=quit): ")
    try:
      num = int(str,16)
      out_word(num)
      clockpulse()
      data = in_data()  # read from Isetta databus
      print("Databus: "+hexfmt(data))
    except ValueError:
      print("Not a hex number")
      err=1


# teststep: execute the microcode. Read the 
#    databus and check if it is the expected value.
# The 'text' argument is printed to screen, so you can see what is going on

def teststep(microcode,testyn,data,text):
  global errorcount
  stopclock()
  out_word(microcode)
  clockpulse()
  n = in_data()
  if (testyn == 1):  # if test-y/n is 0, no data check is done
    if ( n == data ):
      if (test_output ==1):  # added test_output 21-4-2025
        print(text," OK data=",hexfmt(n) )
    else:
      errorcount += 1
      print(text," ERROR data=",hexfmt(n)," but expected ",hexfmt(data) )
      char = input("Give ENTER to continue, Q to quit")
      char = char.lower()
      if (char == 'q'):
        GPIO.cleanup();
        sys.exit()      
  else:
    if (test_output ==1):  # added test_output 21-4-2025
      print(text," data = ",hexfmt(n))


def AutomaticTest():
  # teststep(microcode, testdata y/n, data, text)

  # The following instructions have memory selection bits all 0, that
  # means that the PC addresses the memory. For these tests, it does
  # not matter what the exact location is.

  errorcount = 0

  if (test_output ==1): 
    print("** 1. check incrementing the T register **")

  teststep(0x3D7223,0,0x00,"Set VDU/ to HIGH (74HC259, U13 pin 7)")
  teststep(0x1D7007,0,0x00,"Set pc19 = 0") # 17-11-2025

  teststep(0x000000,0,0x00,"clr T. Not test databus.")
  teststep(0x003000,0,0x00,"Write T to memory")
  teststep(0x2C0000,1,0x00,"inc T, check mem read 0")
  teststep(0x003000,0,0x00,"Write T to memory")
  teststep(0x2C0000,1,0x01,"inc T, check mem read 1")
  teststep(0x003000,0,0x00,"Write T to memory")
  teststep(0x2C0000,1,0x02,"inc T, check mem read 2")

  if (test_output ==1): 
    print("** 2. check databits D0-D7 by doing left-shifts in T register **")

  teststep(0x000000,0,0x00,"clr T")
  teststep(0x2C0000,0,0x00,"inc T")
  n = 1
  while (n <= 0x80): 
    teststep(0x003000,0,0x00,"Write T to memory")
    teststep(0x0D0000,1,n ,"T <- add (T,mem), check mem= "+hexfmt(n))
    n = n + n

  if (test_output ==1): 
    print("** 3. Make an identity table for the values 0x00 - 0xFF **")
  
  # rd/wr to memory location (0|DPL) is microcode xxx122

  teststep(0x000000,0,0x00,"clr T")

  # reg 201 used for value 4
  # reg 202 used for value 128
  # reg 203 used for value 132 (128+4)
  # reg 204 used for value 0x55
  # reg 205 used for value 0xaa
  # 2-11-2024 above registers are in bank0. Move them to bank3:
  # reg 231 used for value 4
  # reg 232 used for value 128
  # reg 233 used for value 132 (128+4)
  # reg 234 used for value 0x55
  # reg 235 used for value 0xaa
  
  n = 0;
  while (n <= 0xFF): 
    teststep(0x0C2000,0,0x00,"DPL <- T")
    #teststep(0x003122,0,0x00,"Write T to (0|DPL)"); # writes to bank 2
    teststep(0x003126,0,0x00,"Write T to (0|DPL)"); # 2-11-2024 set reg2 native, writes to bank 2
    if (n <= 0x29):  # not go higher than needed, that will overwrite 'bank3' registers
      teststep(0x003106,0,0x00,"Write T to (0|DPL)"); # 2-11-2024 writes also to bank 0 <- goes wrong

    if (n==4): 
      teststep(0x003231,0,0x00,"Write 4 to reg 231")
    if (n==16): 
      teststep(0x003236,0,0x00,"Write 0x10 to reg 236") # 15-11-2025
    if (n==128): 
      teststep(0x003232,0,0x00,"Write 128 to reg 232")
    if (n==132): 
      teststep(0x003233,0,0x00,"Write 132 to reg 233")
    if (n==0x55): 
      teststep(0x003234,0,0x00,"Write 0x55 to reg 234")
    if (n==0xaa):     
      teststep(0x003235,0,0x00,"Write 0xaa to reg 235")

    teststep(0x2C0000,0,0x00,"inc T")
    #if (n >=4):
    #  print("T : ",n)  # it goes wrong at n = 0x51
    #  teststep(0x014231,1,0x04,"Read reg 231 from mem, must be 0x04.") # new 2-11. Use A register.
    n = n+1

  # during the further test, dont change registers 201 - 205 ! (now 231 - 235 )

  if (test_output ==1): 
    print("** 4. Check the identity table at a few positions **")

  teststep(0x000000,0,0x00,"clr T")
  teststep(0x2C0000,0,0x00,"inc T")
  n = 1
  while (n <= 0x80): 
    teststep(0x0C2000,0,0x00,"DPL <- T")
    #teststep(0x014122,1,n ,"Read (0|DPL) to A, check it ") # 01
    teststep(0x014126,1,n ,"Read (0|DPL) to A, check it ") # 01 // 2-11 res2, native
    #teststep(0x003207,0,0x00,"Write T to reg207")
    #teststep(0x0D0207,0,0x00 ,"T <- add ( T,reg207 ) ") # SHL(T)
    teststep(0x003237,0,0x00,"Write T to reg207")  # 2-11-2024 use a reg in bank 3
    teststep(0x0D0237,0,0x00 ,"T <- add ( T,reg207 ) ") # SHL(T)
    n = n+n

  if (test_output ==1): 
    print("** 5. check if HW registers A, T, DPL, PCH, PCL are all independent **")

  # 2-11-2024 dont use reg 200, use 240. All following instructions have $ to indicate this

  # No longer use PC to point to mem location, now use a memory-based 
  # register. That means that the microcode is xxx2xx
  teststep(0x000000,0,0x00,"clr T")
  teststep(0x2C0000,0,0x00,"inc T")
  teststep(0x003240,0,0x00,"Write T to memory register")  # $
  teststep(0x0D0240,1,0x01,"T <- add (T,mem), now T=2. Read 1 from mem.") #$


  # write ACC:
  teststep(0x0C4240,0,0x00,"Write T(=2) to register A") # $

  teststep(0x003240,0,0x00,"Write T to memory register")  # $
  teststep(0x0D0240,1,0x02,"T <- add (T,mem), now T=4. Read 2 from mem.") # $

  # write DPL:
  teststep(0x0C2240,0,0x00,"Write T(=4) to register DPL")  # $

  teststep(0x003240,0,0x00,"Write T to memory register") # $
  teststep(0x0D0240,1,0x04,"T <- add (T,mem), now T=8. Read 4 from mem.") # $

  # write PCL:
  teststep(0x0C5240,0,0x00,"Write T(=8) to register PCH but will finally go to PCL") # $

  teststep(0x003240,0,0x00,"Write T to memory register") # $
  teststep(0x0D0240,0,0x00,"T <- add (T,mem), now T=0x10.") # $

  # write PCH:
  teststep(0x0C5240,0,0x00,"Write T(=0x10) to register PCH") # $

  teststep(0x003240,0,0x00,"Write T to memory register") # $
  teststep(0x0D0240,0,0x00,"T <- add (T,mem), now T=0x20.") # $

  # now check the values in the HW registers
  teststep(0x0032C0,0,0x00,"Write A to memory register") # $
  teststep(0x014240,1,0x02,"Read from mem (to A), must be 02.") # check ACC  $

  teststep(0x003240,0,0x00,"Write T to memory register")  # $
  teststep(0x010240,1,0x20,"Read from mem, must be 0x20.") # check T $

  teststep(0x010126,1,0x04,"Read DPL (to T), must be 04"); # check DPL # 2-11-2024 reg2 for native

  teststep(0x010026,1,0x08,"Read PCL (to T), must be 08"); # check PCL # 2-11-2024 reg2 for native

  teststep(0x0C5240,0,0x00,"Write to PCH to get PCH into PCL")  # $

  teststep(0x010026,1,0x10,"Read PCL (to T), must be 0x10"); # check PCH # 2-11-2024 reg2 for native

  # new 2-11-2014 check registers 231-235
  # reg 231 used for value 4
  # reg 232 used for value 128
  # reg 233 used for value 132 (128+4)
  # reg 234 used for value 0x55
  # reg 235 used for value 0xaa
  # reg 236 used for value 0x10  (15-11-2025)

  if (test_output ==1): 
    print("** 6. check the stored values in reg 231..235 **")

  teststep(0x010231,1,0x04,"Read reg 231 from mem, must be 0x04.")
  teststep(0x010232,1,0x80,"Read reg 232 from mem, must be 0x80.")
  teststep(0x010233,1,0x84,"Read reg 233 from mem, must be 0x84.")
  teststep(0x010234,1,0x55,"Read reg 234 from mem, must be 0x55.")
  teststep(0x010235,1,0xaa,"Read reg 235 from mem, must be 0xaa.")
  teststep(0x010236,1,0x10,"Read reg 236 from mem, must be 0x10.")


def addr_test(startstep):
  print("** ",startstep,". Start testing address lines **")

  teststep(0x000000,0,0x00,"clr T") 
  teststep(0x0C1240,0,0x00,"Write T to register DPH")
  teststep(0x2C0000,0,0x00,"inc T") # now T=1 (addr line A0)
  teststep(0x003240,0,0x00,"Store T at reg240") # will shift left after every action
  teststep(0x004000,0,0x00,"clr A") # will increment after every action
  if (startstep >= 100):
    teststep(0x2C4080,0,0x00,"inc A") # slightly different values for 2nd RAM chip
  addr=0
  while (addr < 8): 
    teststep(0x0C2000,0,0x00,"Write T to register DPL") # addresses 0x0001, 0x0002 .. 0x0080
    teststep(0x003180,0,0x00,"Write A to memory DPH/DPL")
    teststep(0x2C4080,0,0x00,"inc A")
    teststep(0x0D0240,0,0x00,"Add reg240 to T") # T shift left
    teststep(0x003240,0,0x00,"Store T at reg240")
    addr += 1
  teststep(0x000000,0,0x00,"clr T") 
  teststep(0x0C2240,0,0x00,"Write T to register DPL")
  teststep(0x2C0000,0,0x00,"inc T") # now T=1 (addr line A0)
  teststep(0x003240,0,0x00,"Store T at reg240") # will shift left after every action
  addr=8
  while (addr < 16): 
    teststep(0x0C1000,0,0x00,"Write T to register DPH") # addresses 0x0100, 0x0200 .. 0x8000
    teststep(0x003180,0,0x00,"Write A to memory DPH/DPL")
    teststep(0x2C4080,0,0x00,"inc A")
    teststep(0x0D0240,0,0x00,"Add reg240 to T") # T shift left
    teststep(0x003240,0,0x00,"Store T at reg240")
    addr += 1

  # positions are filled, now check them
  teststep(0x000000,0,0x00,"clr T") 
  teststep(0x0C1240,0,0x00,"Write T to register DPH")
  teststep(0x2C0000,0,0x00,"inc T") # now T=1 (addr line A0)
  teststep(0x003240,0,0x00,"Store T at reg240") # will shift left after every action
  addr=0
  step = startstep+1
  count=0
  if (startstep >= 100):
    count=1
  while (addr < 8):  # step 50..57
    print("** ",step,". Test address line",addr,"is high **")
    teststep(0x0C2000,0,0x00,"Write T to register DPL")
    teststep(0x014100,1,count,"Read memory at DPH/DPL to A, check it")

    teststep(0x0C5000,0,0x00,"Write T to register PCH (will go to PCL")
    teststep(0x005000,0,0x00,"Write 0 to register PCH")
    teststep(0x014000,1,count,"Read memory at PCH/PCL to A, check it") 

    teststep(0x0D0240,0,0x00,"Add reg240 to T") # T shift left
    teststep(0x003240,0,0x00,"Store T at reg240")
    count += 1
    addr += 1
    step += 1
  teststep(0x000000,0,0x00,"clr T") 
  teststep(0x0C2240,0,0x00,"Write T to register DPL")
  teststep(0x2C0000,0,0x00,"inc T") # now T=1 (addr line A0)
  teststep(0x003240,0,0x00,"Store T at reg240") # will shift left after every action
  addr=8
  step = startstep+9
  #count=0
  while (addr < 16):  # step 58..65
    print("** ",step,". Test address line",addr,"is high **")
    teststep(0x0C1000,0,0x00,"Write T to register DPH")
    teststep(0x014100,1,count,"Read memory DPH/DPL to A, check it")

    teststep(0x005000,0,0x00,"Write 0 to register PCH (will go to PCL")
    teststep(0x0C5000,0,0x00,"Write T to register PCH")
    teststep(0x014000,1,count,"Read memory at PCH/PCL to A, check it") 

    teststep(0x0D0240,0,0x00,"Add reg240 to T") # T shift left
    teststep(0x003240,0,0x00,"Store T at reg240")
    count += 1
    addr += 1
    step += 1




def MoreTests():
  teststep(0x000000,0,0x00,"clr T")
  teststep(0x2C0000,0,0x00,"inc T")
  teststep(0x003240,0,0x00,"Write T to memory register reg240")
  myval=1;
  testnr = 10;
  while (myval < 255):
    print("** ",testnr,". check if HW registers A, T, DPL, PCH, PCL can hold ",hexfmt(myval)," **")
    #write to reg A, DPL, PCH, PCL
    teststep(0x0C4240,0,0x00,"Write T to register A")
    teststep(0x0C2240,0,0x00,"Write T to register DPL")
    teststep(0x0C5240,0,0x00,"Write T to register PCH but will finally go to PCL")
    teststep(0x0C5240,0,0x00,"Write T to register PCH")
    #check registers
    teststep(0x0032C0,0,0x00,"Write A to memory register 240") 
    teststep(0x014240,1,myval,"Read from mem (to A), must be VAL")
    teststep(0x010126,1,myval,"Read DPL (to T), must be VAL");
    teststep(0x010026,1,myval,"Read PCL (to T), must be VAL");
    teststep(0x0C5240,0,0x00,"Write to PCH to get PCH into PCL")
    teststep(0x010026,1,myval,"Read PCL (to T), must be VAL");

    teststep(0x003240,0,0x00,"Write T to memory register") # T = T << 2
    teststep(0x0D0240,0,0x00,"T <- add (T,mem), double T") # T = T << 2
    myval += myval  # repeat for next bit 
    testnr += 1

  print("** 18. test condition tc and dtc **")
  # the last step ( T << 2) produced TC = 1 and T = 0, and left 0x80 in reg 240
  # first test tc=1
  teststep(0x6C0000,0,0x00,"Add TC(carry) to T")  # this also moves tc into dtc
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x01,"Read from mem (to A), must be 0x01 (tc=1)")
  # now test dtc=1
  teststep(0x010240,0,0x01,"Read 0x80 from reg 240 to T")
  teststep(0x0D0240,0,0x01,"Add 0x80 from reg 240 to T") # gives T=0, tc=1
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, does dtc <- tc")
  teststep(0xCC0000,0,0x00,"Add DTC(carry) to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x01,"Read from mem (to A), must be 0x01 ( T + dtc )")
  # now test tc=0. 
  teststep(0x000000,0,0x00,"clr T")  # will clr T and produce tc=0
  teststep(0x6C0000,0,0x00,"Add TC(carry) to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x00,"Read from mem (to A), must be 0x00 (tc=0)")
  # now test dtc=0
  teststep(0x000000,0,0x00,"clr T")  # will clr T and produce tc=0
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, does dtc <- tc")
  teststep(0xCC0000,0,0x00,"Add DTC(carry) to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x00,"Read from mem (to A), must be 0x00 ( T + dtc )")

  print("** 19. test cy flag **")
  # now test cy=1
  teststep(0x010240,0,0x01,"Read 0x80 from reg 240 to T")
  teststep(0x0D8240,0,0x01,"Add 0x80 from reg 240 to T, upd_c") # gives T=0, cy=1
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting cy")
  teststep(0x4C0000,0,0x00,"Add cy to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x01,"Read from mem (to A), must be 0x01 ( T + cy )")
  # now test cy=0. 
  teststep(0x000000,0,0x00,"clr T")  # will clr T
  teststep(0x0D8240,0,0x01,"Add 0x80 from reg 240 to T, upd_c") # gives T=0x80, cy=0
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting cy")
  teststep(0x4C0000,0,0x00,"Add cy to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x80,"Read from mem (to A), must be 0x80 ( T + cy )")

  print("** 20. test n flag **")
  # now test n=1
  teststep(0x010640,0,0x01,"Read 0x80 from reg 240 to T, upd_n")
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting n")
  teststep(0x8C0000,0,0x00,"Add n to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x81,"Read from mem (to A), must be 0x81 ( T + n )")
  # now test n=0. 
  teststep(0x000400,0,0x00,"clr T, upd_n")  # will clr T
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting n")
  teststep(0x8C0000,0,0x00,"Add n to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x00,"Read from mem (to A), must be 0x00 ( T + cy )")

  print("** 21. test resultbus bit0 **") # used to get the cy in shift-right instructions
  # now test bit0=1
  # T register is still 0
  teststep(0x2C0000,0,0x00,"inc T") # this produces a 1 in bit0, and T=1
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,0,0x00,"Read from mem (to A), bit0 is of interest")
  teststep(0xA1C241,0,0x01,"Read from mem (to A), used as NOP, upd_c will put the bit in cy")
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting cy")
  teststep(0x4C0000,0,0x00,"Add cy to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x02,"Read from mem (to A), must be 0x02 ( T + bit0 )")
  # now test bit0=0 
  teststep(0x000000,0,0x00,"clr T")  # will clr T, 0 in bit0
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,0,0x00,"Read from mem (to A), bit0 is of interest")
  teststep(0xA1C241,0,0x01,"Read from mem (to A), used as NOP, upd_c will put the bit in cy")
  teststep(0x014241,0,0x01,"Read from mem (to A), used as NOP, extra cycle after setting cy")
  teststep(0x4C0000,0,0x00,"Add cy to T") 
  teststep(0x003241,0,0x00,"Write T to memory register reg241")
  teststep(0x014241,1,0x00,"Read from mem (to A), must be 0x00 ( T + bit0 )")

  print("** 22. Start of 64k bank switching tests **")
  teststep(0x1D7001,0,0x00,"set slot3/pc17 = 0") # bankswitching in slot 1 (#4000-7FFF)
  teststep(0x1D7004,0,0x00,"set pc18 = 0")
  teststep(0x004000,0,0x00,"clr A")
  teststep(0x0C22C0,0,0x00,"Write A to register DPL")
  teststep(0x0C52C0,0,0x00,"Write A to register PCH but will finally go to PCL")
  teststep(0x015234,1,0x55,"Read reg 234 (0x55), write it to PCH") # check if it is still 0x55
  bank=0
  while (bank < 8):
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write banknr, also writes DPH
    teststep(0x011234,0,0x00,"Read reg 234 (0x55), write it to DPH")
    teststep(0x003180,0,0x00,"Write A to memory DPH/DPL in selected bank")
    teststep(0x2C4080,0,0x00,"inc A")
    bank += 1
  teststep(0x004000,0,0x00,"clr A")
  bank=0
  step = 23
  while (bank < 8):  # step 23..30
    print("** ",step,". Bankswitching, bank",bank,"slot1 **")
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write banknr, also writes DPH
    teststep(0x011234,0,0x55,"Read reg 234 (0x55), write it to DPH")
    teststep(0x010180,1,bank,"Read memory DPH/DPL in selected bank to T, check it")
    if (bank==4):
        teststep(0x3D7004,0,0x00,"set pc18 = 1")
    teststep(0x010080,1,bank,"Read memory PCH/PCL in selected bank to T, check it")
    teststep(0x2C4080,0,0x00,"inc A")
    bank += 1
    step += 1
 
  teststep(0x1D7004,0,0x00,"set pc18 = 0")
  # in native mode, data will appear at msb = 0x15
  teststep(0x010231,0,0x00,"Read reg231 (0x04) to T")
  teststep(0x2C0000,0,0x00,"inc T") # now T=5
  teststep(0x0D0236,1,0x10,"Add 0x10 to T") # now T=0x15
  teststep(0x0C1240,0,0x00,"Write T to register DPH")
  teststep(0x015026,0,0x00,"Read PCL and write it to PCH");
  teststep(0x0C5240,0,0x00,"Write T to register PCH")
  bank=0
  step = 31
  while (bank < 4):  # step 31..34
    print("** ",step,". Native mode, bank",bank," **")
    teststep(0x014104+16*bank,1,bank,"Read memory DPH/DPL in selected bank to A, check it")
    teststep(0x014004+16*bank,1,bank,"Read memory PCH/PCL in selected bank to A, check it")   
    bank += 1
    step += 1

  print("** 35. Test Application mode **")
  # write 0x40 to BNK register to set addr mode
  teststep(0x014236,0,0x01,"Read 0x10 from mem (to A)")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A giving 0x40") 
  bank=0
  step = 36
  while (bank < 8):  # step 36..43
    print("** ",step,". Application addressing, bank",bank," **")
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write banknr, also writes DPH
    teststep(0x0C1240,0,0x00,"Write T (0x15) to register DPH")
    teststep(0x015180,1,bank,"Read memory DPH/DPL in selected block to PCH, check it") # PCH not used
    teststep(0x2C4080,0,0x00,"inc A")
    bank += 1
    step += 1

  print("** 44. Start of 16K block addressing tests **")
  teststep(0x004000,0,0x00,"clr A")
  block=0
  while (block < 4):
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write blocknr+banknr, also writes DPH
    teststep(0x011234,0,0x00,"Read reg 234 (0x55), write it to DPH")
    teststep(0x003180,0,0x00,"Write A to memory DPH/DPL in selected block")
    # now add 0x10 to A, to select next block
    teststep(0x0D42B6,1,0x10,"Add 0x10 to A")
    block += 1  
  teststep(0x004000,0,0x00,"clr A")
  block=0
  step = 45
  while (block < 4):  # step 45..48
    print("** ",step,". Block addressing, block",block," **")
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write blocknr+banknr, also writes DPH
    teststep(0x011234,0,0x55,"Read reg 234 (0x55), write it to DPH")
    teststep(0x010180,1,16*block,"Read memory DPH/DPL in selected block to T, check it")
    # now add 0x10 to A, to select next block
    teststep(0x0D42B6,1,0x10,"Add 0x10 to A")
    block += 1
    step += 1
  teststep(0x014236,0,0x01,"Read 0x10 from mem (to A)")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A giving 0x40") 
  teststep(0x2C4080,0,0x00,"inc A") # appl=1, bank=1
  teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write blocknr+banknr, also writes DPH
  addr_test(49) # test 49..65

  #to do: test EXX signal. Test U55 pin7 (ES).

  print()
  print("** ",99,". All tests are executed. ",errorcount," error(s). **")

  print()
  print("** ",100,". Now check if 1024 kByte is present **")

  print("** 64k bank switching tests for 1 MByte **")
  teststep(0x1D7001,0,0x00,"set slot3/pc17 = 0") # bankswitching in slot 1 (#4000-7FFF)
  teststep(0x1D7004,0,0x00,"set pc18 = 0")
  teststep(0x004000,0,0x00,"clr A")
  teststep(0x0C22C0,0,0x00,"Write A to register DPL")
  teststep(0x0C52C0,0,0x00,"Write A to register PCH but will finally go to PCL")
  teststep(0x015234,1,0x55,"Read reg 234 (0x55), write it to PCH") # check if it is still 0x55
  bank=0
  while (bank < 16):
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write banknr, also writes DPH
    teststep(0x011234,0,0x00,"Read reg 234 (0x55), write it to DPH")
    teststep(0x003180,0,0x00,"Write A to memory DPH/DPL in selected bank")
    teststep(0x2C4080,0,0x00,"inc A")
    bank += 1
  teststep(0x004000,0,0x00,"clr A")

  if (errorcount==0):
      print()
      print("**** For a 512k RAM Isetta, all tests succeeded.          ****")
      print("**** The following tests are only for the 1024k RAM model ****")
      print()

  bank=0
  step = 101
  while (bank < 16):  # step 101..116
    print("** ",step,". Bankswitching 1 MByte, bank",bank,"slot1 **")
    teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write banknr, also writes DPH
    teststep(0x011234,0,0x55,"Read reg 234 (0x55), write it to DPH")
    teststep(0x010180,1,bank,"Read memory DPH/DPL in selected bank to T, check it")
    #if (bank==4):
    #    teststep(0x3D7004,0,0x00,"set pc18 = 1")
    #teststep(0x010080,1,bank,"Read memory PCH/PCL in selected bank to T, check it")
    teststep(0x2C4080,0,0x00,"inc A")
    bank += 1
    step += 1
  teststep(0x3D7007,0,0x00,"Set pc19 = 1") # 18-11-2025 select 2nd 512K chip for PC
  teststep(0x014236,0,0x01,"Read 0x10 from mem (to A)")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A")
  teststep(0x0D42B6,0,0x10,"Add 0x10 to A giving 0x40") 
  teststep(0x0D42B1,0,0x10,"Add 0x04 to A")
  teststep(0x0D42B1,0,0x10,"Add 0x04 to A giving 0x48") # select a19=1 for dph/dpl
  teststep(0x2C4080,0,0x00,"inc A") # appl=1, bank=9
  teststep(0x0C12C0,0,0x00,"Write A to BNK register") # write blocknr+banknr, also writes DPH
  addr_test(117) # test the address lines of the 2nd RAM (test 117..133)
  print("** 134. check databits D0-D7 in 2nd RAM **")

  teststep(0x000000,0,0x00,"clr T")
  teststep(0x2C0000,0,0x00,"inc T")
  n = 1
  while (n <= 0x80): 
    teststep(0x003000,0,0x00,"Write T to memory")
    teststep(0x0D42B1,0,0x10,"Add 0x04 to A") # discharge data lines
    teststep(0x0D0000,1,n ,"T <- add (T,mem), check mem= "+hexfmt(n))
    n = n + n

  if (errorcount==0):
      print()
      print("****   All tests succeeded.    ****")
      print()


############################################################

'''
def do_date_time():
  current = datetime.now()
  #current has format: 2024-05-09 19:48:13.138440
  #print(current)
  # remove "-", space and ":"
  
  newtime = str(current).replace('-','').replace(' ','').replace(':','')
  #newtime = str(current).replace('-',' ').replace(':',' ')

  newtime = newtime.split(".",1)[0]  # forget everything after the dot
  #print(newtime)
  return newtime
'''
# 24-5-2024 change to binary (instead of bcd)

def tstr(input):  # input 20 -> output 14 (hex binary, 16+4)
  input = input + 128  # 26-5-2024 set bit 7
  s = hex(input)
  s =  s[2:]   # remove "0x" at the beginning
  #if (input<16):
  #  s = "0"+s # add prefix "0" when below 16, to get two characters
  #print("-"+s)  # debug
  return s

def do_date_time():
  c = datetime.now()
  #c has format: 2024-05-09 19:48:13.138440
 
  s = tstr(20) + tstr(c.year-2000) + tstr(c.month) +tstr(c.day)
  s = s + tstr(c.hour) + tstr(c.minute)+tstr(c.second)

  return str(s)

############################################################

# start main program

print("start programmer. ")

init_gpio()
idle()

if (GPIO.input(IS_ON) == 0):
  print("The Isetta is not present or not switched ON  ")
  print("Switch the Isetta ON. (Only connect it when RPi is OFF)")
  print("Exit programmer.")
  GPIO.cleanup();
  sys.exit()  # terminate program


# command loop

while (running):
  print()
  print("isetta_rpi programming and debugging")
  #print(do_date_time())
  print()
  print("Version "+version)
  print()
  print("---- Menu ----")

  print("A    Automatic test")
  print("Z    Flash chip ID ")
  print("S    Stop Isetta clock")
  print("U    Give Microcode command")
  print("E    Erase ALL ")
  print("P    Program ucode file ")
  print("V    Verify ucode file")
  print("Y    single step")
  print("K    send ^C")
  print("X    eXecute on Isetta") 

  print("Q    Quit  ")

  try:
    char = input("Type command followed by ENTER>>")
  except KeyboardInterrupt:
    idle()
    GPIO.cleanup();
    print()
    print(" ^C  end programmer")
    sys.exit()  # terminate program

  char = char.lower()
  print("-----------------------------------------------------------")

  if (char=="c"):  
    clockcommand()  # was: clockpulse
  if (char=="s"):  
    stopclock()
  if (char=="u"):  
    MicrocodeIsetta()
  if (char=="a"):  
    test_output=1
    AutomaticTest()
    MoreTests() # 13-11-2025
  if (char=="y"):  
    Singlestep()
  if (char=="k"):  
    dummy=chartransfer(3)  # send ^c


# if (char[0]=="f"):  # input returns  [char num]
#   fetch_comm(char)
  if (char=="r"):
    page_display()
# manual cpu control: instruction, mem_read, write. char can also be string.
  if (char[0]=="i"):
    instruction(char)
  if (char[0]=="m"):
    mem_read(char)
  if (char=="w"):
    mem_write()
# 21-1-2020 two new commands
  if (char=="j"):
    j_instruction(char)
  if (char=="n"):
    new_mem_read(char)
#    page = page + 0x0100
#    page_display()
#  if (char=="d"):
#    page = page - 0x0100
#    page_display()

  if (char=="z"):
    show_id()
  if (char=="q"):
    running=0
  if (char=="x"):
    exec_isetta() 
  if (char=="p"):  
    dofile("p")
  if (char=="v"):  
    dofile("v")
  if (char=="f"):
    dir = "/home/pi/Downloads/"
    print("No need to enter extension (.hex) and directory ("+dir+")" )
    str = input("filename: ")
    newname= dir + str +".hex"
    #check for 'time only' input: HMMS  <a-z><0-2><0-9><a-z>
    if (len(str)==4):
      print("length=4")
      regex= re.compile("[a-z][0-5][0-9][a-z]")
      m = regex.match(str)
      if m:   # if regex matches
        print("match ok") # so str is the new time code
        filename = filename.split(".")[0]  # remove extension
        split = filename.split("_")  # split old name in two sections
        lastpart = split[1][:-4]   # remove last 4 chars
        firstpart = split[0]
        # construct new filename
        newname = firstpart+"_"+lastpart+str+".hex"
             
    filename = newname;
    fileinfo=file_info()
  if (char=="e"):  
    erase_all()
  
  


 
idle()
GPIO.cleanup();
print("end programmer")
sys.exit()  # terminate program


