Coding tests for Vetus Pars

VETUS PARS RETRO CHIP TESTER
TEST CODE WRITING MANUAL

*Attention* here is a new 6502 test file with comments to show you how to work with CPUs like the 6502.

1.  Introduction

The Vetus Pars Retro Chip Tester uses an interpreted instruction system.
Every chip test is written as a list of instructions, one per line, each consisting of:

OPCODE ARG1 ARG2 ARG3

The Vetus GUI software converts these text instructions into 32-bit program words and uploads them to the device. The Vetus Pars then executes the instructions to test the chip installed in the ZIF socket.

End users may write their test scripts manually using any text editor they prefer (Notepad, TextEdit, Sublime, VS Code, etc.), as long as they follow the formatting rules described here.
However, the Vetus GUI will insert opcode values automatically if they select instructions from the provided menus.

2.  Required Tools

Two things are required to develop or test chip scripts:
1. The Vetus GUI software
• Used to upload new chip definitions, images, metadata, and test code.
• Used to run tests interactively while developing a script.
2. A plain text editor (optional)
• If users prefer to write tests manually.
• The GUI can load and import these files.

3.  File Format for Test Scripts

A test script is a plain text file containing:
1. A header line:
META:
2. A second header:
CODE:
3. Lines of instructions:
OPCODE ARG1 ARG2 ARG3 – please note that even if the argument is not used you must use 0x0 at least when using each opcode. For instance, if you use ENDTEST which takes no arguments, you still need to add all three arguments. Ex: ENDTEST 0x0 0x0 0x0

The GUI software will validate and convert this into program code automatically.

4.  Opcode Byte Values

Each instruction corresponds to a single opcode byte (the low byte of the first program word).
Here are the opcodes and their byte values:

SETPIN: 0x01

SETIN: 0x02

SETOUT: 0x09

RDPIN: 0x03

MULTIO: 0x05

MULTII: 0x06

MULTIHI: 0x07

MULTILO: 0x08

ASAFE: 0x0B

GOSTRT: 0x0D

ALLDIR: 0x0E

ALLEVEL: 0x0F

DEFADDR: 0x22

SETADDR: 0x21

ADDRBIT: 0x20

ADDRCLR: 0x2

LOOP: 0x10

ENDLOOP: 0x11

BRKLOOP: 0x13

DELUS: 0x16

DELMS: 0x17

WHILE: 0x18

ENDWHL: 0x19

JMP: 0x1A

DOUNTIL: 0x1B

ENDUNTIL: 0x1C

CLKST: 0x1D

CLKSTP: 0x1E

IF: 0x50

ENDIF: 0x51

LEDON: 0x6C

LEDOFF: 0x6D

REGLOD: 0x40

REGCLR: 0x41

REGINC: 0x42

REGDEC: 0x43

ADD: 0x44

SUBTR: 0x45

MULT: 0x46

DIV: 0x47

RNG: 0x49

AND: 0x4A

OR: 0x4B

SHL: 0x4C

SHR: 0x4D

NOT: 0x4E

XOR: 0x4F

BTNPR: 0x6A

BTNWT: 0x6B

FILSCR: 0x61

SHOSTR: 0x60

TXTCOL: 0x63

PROG: 0x64

UDSCRN: 0x6F

PASSFAIL: 0xF2

ENDTEST: 0xF0

BLNKON: 0x68

BLNKOFF: 0x69

FANON: 0x24

ARRADD: 0x25

ARRGET: 0x26

GETADDR: 0x27

PHIZ: 0x28

TOGPIN: 0x29

PIN2ARR: 0x2A

DEF8: 0x2B

SET8: 0x2C

GET8: 0x2D

5.  Registers

The Vetus Pars test engine has 32 registers named R0 through R31.

To reference a register, prefix with “#”:

#R0

#R1

#R2… and so forth up to 32 registers total.

Registers hold numbers, loop counters, results from GETADDR, GET8, or values read from pins.

In code, if you are getting a value from the register then you need to use #Rn where n is the register number. If you are doing anything to a register other then using its value then you should simply use the register number for the argument.

6.  DEF8 / SET8 / GET8 Table System

Many chips use lookup tables for writing or verifying patterns.

DEF8 index value extra
Defines an 8-bit entry.

SET8 index value flags
Writes a value to the DEF8 entry or to the chip pins depending on the definition.

GET8 dstIndex srcIndex flags
Reads from the table and stores the result in R(dstIndex).

Example:
DEF8 0x0 0x1020304 0x1011
SET8 0x2 0xF 0x1
GET8 0x2 0x2 0x0

7.  Pin Control Instructions

ALLDIR sets direction for all pins at once.
ALLEVEL sets initial logic levels for output pins.
SETPIN controls one pin at a time.
DELUS waits for microseconds.
DELMS waits for milliseconds.

SETOUT sets a pin as output.

SETIN sets the pin as input

Example:
SETPIN 0x8 0x1 0x0
DELUS 0x10 0x0 0x0
SETPIN 0x8 0x0 0x0

SETOUT 0x1 0x0 0x0
SETIN 0xA 0x0 0x0

8.  Loops

LOOP num. empty empty
ENDLOOP ends the loop.
The internal counter decreases automatically.

Example:
LOOP 0x10 0x0 0x0
SET8 0x2 0xF 0x1
ENDLOOP 0x0 0x0 0x0

Loops the code inside of it 16 times (0x10)

9.  Conditionals

IF condition value value
ENDIF

Example:
IF 0x1 #R2 0xF
PASSFAIL 0x0 0x0 0x0
ENDTEST 0x0 0x0 0x0
ENDIF

This would mean, if register2 is NOT equal to 15 (0xF)

10. Display Output

The tester has a built-in text display.
Use these to show results or messages during testing:

SHOSTR stringIndex x y
UDSCRN 0x0 0x0 0x0
TXTCOL (if text color is supported in your firmware)

Example:
SHOSTR 0x0 0x0 0x30
UDSCRN 0x0 0x0 0x0

11. Finishing the Test

Every program must end with ENDTEST in order to exit the test:

ENDTEST 0x1 0x0 0x0

If PASSFAIL was set to 1 it will pass. Setting it to 0 for failure.

12. Full Example Test (Copy-Paste Friendly)

Below is a complete example test similar to a DRAM walking pattern. No code box formatting is used so it can be copied directly.

[chipfile]
type = single

[chips]


[meta]

name = 4164 RAM
pins = 16
type = 1
imageIndex = 3

[code]

PASSFAIL 0x1 0x0 0x0
ALLDIR 0x1FF 0x1FF 0x0
ALLEVEL 0x80 0x101 0x0

DEF8 0x0 0x1020304 0x1011
DEF8 0x1 0xF070605 0x0
DEF8 0x2 0xB0C0D0E 0x0

REGLOD 0x0 0x0 0x0
REGLOD 0x1 0x0 0x0

SETPIN 0x8 0x0 0x0
SETPIN 0x10 0x1 0x0

SET8 0x2 0xF 0x1

LOOP 0x100 0x0 0x0
SET8 0x2 0xF 0x1
ENDLOOP 0x0 0x0 0x0

SHOSTR 0x0 0x0 0x30
DELMS 0x2 0x0 0x0
UDSCRN 0x0 0x0 0x0

LOOP 0xF 0x0 0x0
SET8 0x0 #R0 1×0
SET8 0x1 #R1 0x1
SETPIN 0x10 0x0 0x0
DELUS 0x10 0x0 0x0
SETPIN 0x10 0x1 0x0
REGINC 0x1 0x0 0x0
ENDLOOP 0x0 0x0 0x0

SET8 0x2 0xFF 0x0
REGLOD 1×0 0x0 0x0

LOOP 0xF 0x0 0x0
SET8 0x1 #R1 0x1
GET8 0x2 0x2 0x0
IF 0x1 #R2 0xF
PASSFAIL 0x0 0x0 0x0
ENDTEST 0x0 0x0 0x0
ENDIF 0x0 0x0 0x0
DELMS 0x1 0x0 0x0
REGINC 0x1 0x0 0x0
ENDLOOP 0x0 0x0 0x0

SHOSTR 0x1 0x0 0x48
DELMS 0x2 0x0 0x0
UDSCRN 0x0 0x0 0x0

ENDTEST 0x0 0x0 0x0

13. Uploading and Testing

The GUI must be used for:

  • uploading new chip metadata
  • uploading pin maps
  • uploading test code
  • uploading images
  • validating text scripts
  • running test code on the device
  • debugging test output in real-time

The device imports scripts via USB through the Vetus GUI app.

VETUS PARS — FULL ADDRESSING SYSTEM (WITH GETADDR)

The Vetus Pars uses a flexible, universal addressing system because different chips handle addressing in different ways. Some have a full 16-bit bus (SRAM/EPROM), some are multiplexed (DRAM), some use small 3–8-bit “select lines” (decoders, multiplexers), and some only need simple bit-toggling.

To support all of these, the tester implements three addressing systems:
1. DEFADDR / SETADDR / GETADDR / ADDRBIT — full 16-bit addressing
2. DEF8 / SET8 / GET8 — small 8-bit address groups
3. Manual per-pin control — for unconventional chips

____________________________________________________________


WHAT ADDRESSING ACTUALLY MEANS

Addressing is simply a way to choose one item out of many.

For example:

  • In SRAM, the address pins A0–Axx select which memory cell to read.
  • In EPROMs, the address chooses which byte is output on D0–D7.
  • In DRAM, the address is split into row and column (multiplexed).
  • In 74HC138, the inputs A/B/C select which output goes LOW.
  • In a multiplexer like CD4051, the address selects which input is routed out.

The Vetus Pars must therefore drive address pins very precisely.

____________________________________________________________


ADDRESS SYSTEM 1:
16-BIT ADDRESS BUS (DEFADDR / SETADDR / GETADDR / ADDRBIT)

This is the main addressing system for large memory chips and structured logic.

It supports a full 16-bit virtual address bus: A0 through A15.

HOW TO THINK ABOUT IT

You tell the tester:

  • Which chip pins are A0–A15
  • What value you want on those address lines
  • What direction each pin should be (input or output) – As related to the tester. If the chip pin needs an input then you want to OUTPUT from the tester.

The tester handles the ZIF mapping automatically based on the chip’s pin count (important!).

DEFADDR — Define Chip Pin Positions for A0–A15

Correct argument meaning:

  • Argument 1 chooses LOW or HIGH address byte
    0x0 = define A0–A7
    0x8 = define A8–A15
  • Argument 2 = four packed chip pins for the first four address bits
  • Argument 3 = four packed chip pins for the next four address bits

Example of packed format for Arg2:
0x04030201 means:
A0 = pin 1
A1 = pin 2
A2 = pin 3
A3 = pin 4

The important part:
Each packed 32-bit value holds exactly 4 chip pin numbers, each of which must be 2-digit hex values. The tester uses the chip’s pin count from metadata to remap these automatically to ZIF pins.

SETADDR — Send a 16-Bit Address

Arguments:

  • Arg1 = number of bits to drive (2-8)
  • Arg2 = address byte (0x00–0xFF)
  • Arg3 = direction (0 for input, 1 for output) <~ Again: input or output to/from the Vetus Pars tester.

SETADDR 0x8 0xFF 0X1 -> set the address to 255 output.

Before reading from a chip:

  • Set Arg3 = 0 (input mode)
    This avoids bus contention when the chip drives data lines. The read function automatically set the pins to input but it’s preferred to add this anyway as a precaution.

GETADDR — Read the Current Address Bits Into a Register

GETADDR reads the defined address lines that were configured using DEFADDR (or ADDRBIT) and places the resulting 8-bit value into one of the tester’s registers.

Correct arguments:

  • Arg1 = bit count (0–8), meaning how many address bits you want to read
  • Arg2 = register number to store the result
  • Arg3 = 0 (reserved, unused but must exist)

The tester reads the physical chip pins, applies the DEFADDR mapping, and assembles the result into an 8-bit value stored in the register.

Typical uses:

  • Verify that a counter chip is producing address lines correctly
  • Confirm the correct address appears after DRAM RAS/CAS strobes
  • Debug address decode logic
  • Detect stuck address pins
  • Reading data from data pins

ADDRBIT — Define or Override One Address Bit

Arguments:

  • Arg1 = bit number (0–15)
  • Arg2 = chip pin number

ADDRBIT is useful for:

  • Fixing one bad mapping
  • Supporting weirdly pinned chips
  • Dynamic reconfiguration
  • Row/column testing in DRAM

________________________________________________________


ADDRESS SYSTEM 2:
8-BIT ADDRESS GROUPS (DEF8 / SET8 / GET8)

DEF8 gives the tester fast, compact addressing banks used for many logic chips.

This system is ideal for:

  • 74HC138
  • 74HC154
  • 4051 multiplexers
  • 74HC157
  • Many ALUs
  • Small ROM lookup tables
  • DRAM row/column high-level helpers

DEF8 — Define an 8-Bit Address Bank

Arguments:

  • Arg1 = index of the 8-bit bank
  • Arg2 = chip pins for low nibble A0–A3
  • Arg3 = chip pins for high nibble A4–A7

The pins are in the same packed 32-bit format as DEFADDR.

Each DEF8 bank is like a small “virtual port” that can be reused anywhere in the test.

SET8 — Drive an 8-Bit Value Onto the Bank

Arguments:

  • Arg1 = number of bits to write (0–8)
  • Arg2 = value to output (0–255)
  • Arg3 = direction (0=input, 1=output)

Most common pattern:

  • Set direction = 1 before writing
  • Set direction = 0 before reading

GET8 — Read 8 Bits From a DEF8 Bank Into a Register

Arguments:

  • Arg1 = DEF8 index
  • Arg2 = output register
  • Arg3 = reserved (0)

This:

  • Reads the actual physical chip pins as mapped by DEF8
  • Packs them into a byte
  • Stores them in a register

Useful for:

  • Testing counters
  • Reading DRAM sense lines
  • Reading multiplexer outputs
  • Verifying correct logic state sequences

_______________________________________________________


CHOOSING BETWEEN DEFADDR AND DEF8

Use DEFADDR / SETADDR / GETADDR when:

  • Chip has more than 8 address pins
  • You need true 16-bit addressing
  • You are testing SRAM/EPROM/DRAM/large ROM
  • You need classical A0–Axx behavior

Use DEF8 / SET8 / GET8 when:

  • Chip only has 2–8 address pins
  • You are making repeated index lookups
  • You want fast looping and compact test code
  • You want simple nibble-based mapping

ALLDIR AND ALLEVEL QUICK GUIDE

────────────────────────────────────

These two instructions handle all address/data/control pins at once using a single binary mask.

They affect every defined pin in your chip’s metadata pin map.

You express pin direction or pin level using a binary pattern such as:

0b00000000

0b11111111

0b10101010

0b00001111

0b00110011

Each bit corresponds to ONE chip pin with SideA (whole left side starting at pin 1) being argument1 and SideB (the pin higher numbers) being argument2. The pins go from top of the chip to the bottom of the chip for each side starting with the LSB (far right) Ex: 0b00000001 The 1 here would be pin #1. If we were doing SideB then 1 would be the highest numbered pin on the chip whatever number that happens to be. You can input these as HEX, Decimal or Binary. It is easier however to use binary as each bit represents a chip pin. Vetus GUI will automatically translate it to HEX, which is what it must be saved as.

────────────────────────────────────

SETTING ALL PIN DIRECTIONS (ALLDIR)

Instruction meaning:

ALLDIR sets whether each test pin is input (read) or output (drive).

Binary meaning:

0 = Input (high-impedance, listening)

1 = Output (driving logic level)

Example meaning:

0b00000000

Every pin is input (safe mode for first power-up)

0b11111111

Every pin is output (only safe if truly required)

0b11110000

Upper 4 pins output, lower 4 pins input

When to use it:

• Just before test begins to safely define pin roles

• To switch bus between read cycles and write cycles

• Before reading memory, all address pins should be outputs, data pins inputs

SETTING ALL PIN LEVELS (ALLEVEL)

Instruction meaning:

ALLEVEL sets logic HIGH/LOW on every output pin defined in metadata.

Binary meaning:

0 = logic LOW

1 = logic HIGH

Example meanings:

0b00001111

Lower pins HIGH, upper pins LOW

0b10101010

Alternating pattern HIGH/LOW

0b11111111

All HIGH

When to use:

• Apply full address lines at once

• Pre-charge DRAM

• Enable control signals in a single step

• Drive entire bus pattern for comparison, ALU chips, ROM selects, etc.

SAFETY RULE

When unsure, ALWAYS begin with:

ALLDIR = 0b00000000

All pins high-Z input, nothing driven.

Then selectively drive only what is required.

Never set ALLDIR to all outputs against a powered chip unless you know every bus line is safe to assert simultaneously.

PRACTICAL FLOW DURING TESTING

Typical scan sequence:

  1. ALLDIR → 0b00000000 (all input, safe) or ALLSAFE (this sets every pin to HI-Z)
  2. ALLDIR → set address pins output, data pins input
  3. ALLEVEL → drive full address and control pattern
  4. Read data pins
  5. Change address pattern
  6. Repeat

For write-capable memory:

  1. ALLDIR → set address + data pins output
  2. ALLEVEL → drive write data
  3. Pulse write enable
  4. Switch data pins back to input (ALLDIR)
  5. Read to verify

WHY BINARY IS USED INSTEAD OF HEX

Binary directly reflects physical bus states.

You can visually see which pins are:

1 → driving logic high

0 → low or high-Z depending on DIR mode

It prevents confusion and speeds debugging.