227 INTERCAL ALU

227 : INTERCAL ALU

Design render

How it works

As an educational project, it is inevitable that Tiny Tapeout would attract various pedagogical examples of common logic circuits, such as ALUs. While ALUs for common operations such as addition, subtraction, and binary bitwise logic are surprisingly common, it is much rarer to encounter one that can calculate the five operations of the INTERCAL programming language. Due to either the cost-prohibitive nature of Warmenhovian logic gates or general lack of interest, such a feat has never been performed until now. With chip production finally within reach of the average person, all it takes is one person who has more dollars than sense to design the fabled INTERCAL ALU (Arrhythmic Logic Unit).

The pin assignments for this design are roughly as follows. The /OE (output enable) and /WE (write enable) signals are active low, so should be set HIGH by default.

# Dedicated Input Dedicated Output Bidirectional I/O
0 A0 (address) D0 (output only) D0 (input and output only)
1 A1 (address) D1 (output only) D1 (input and output only)
2 S0 (selector) D2 (output only) D2 (input and output only)
3 S1 (selector) D3 (output only) D3 (input and output only)
4 S2 (selector) D4 (output only) D4 (input and output only)
5 S3 (selector) D5 (output only) D5 (input and output only)
6 /OE (output enable) D6 (output only) D6 (input and output only)
7 /WE (write enable) D7 (output only) D7 (input and output only)

This ALU has two 32-bit registers, B and A (in no particular order). (These may also be thought of as four 16-bit registers, AL, AH, BL, and BH.) To write a byte to a register, set A0 and A1 to the byte address, set S0 LOW for the A register or HIGH for the B register, set S1 through S3 LOW, set the bidirectional I/O pins to the byte value, set /WE LOW, then set /WE HIGH again. (Do not set S1 through S3 HIGH when writing, or else something unpredictable will happen, most likely nothing.)

To read a register or result, set A0 and A1 to the byte address, set S0 through S3 to the desired operation, set /OE LOW, read the byte value from the bidirectional I/O pins, then set /OE HIGH. Results can also be read from the dedicated outputs; the dedicated outputs are not affected by the /OE signal, as they do not need to care about your feelings.

The operations supported are listed below. An attempt was made to make it understandable.

Operations 0 and 1 simply return the current value of the A or B register, respectively. This corresponds with the values of S0 through S3 used in write mode. This is not unintentional. This might also explain why S1 through S3 must be LOW in write mode.

Operations 2 through 7 correspond to INTERCAL's unary AND, unary OR, and unary XOR operators, represented by ampersand (&), book (V), and what (?), respectively. From the INTERCAL manual:

<blockquote> These operators perform their respective logical operations on all pairs of adjacent bits, the result from the first and last bits going into the first bit of the result. The effect is that of rotating the operand one place to the right and ANDing, ORing, or XORing with its initial value. Thus, <code>#&77</code> (binary = 1001101) is binary 0000000000000100 = 4, <code>#V77</code> is binary 1000000001101111 = 32879, and <code>#?77</code> is binary 1000000001101011 = 32875. </blockquote>

Operations 2, 4, and 6 work on the 16-bit halves of the A register independently, while operations 3, 5, and 7 work on the 32-bit whole of the A register.

Operations 8 and 9 correspond to INTERCAL's interleave (also called mingle) operator, represented by big money ($). From the INTERCAL manual:

<blockquote> The interleave operator takes two 16-bit values and produces a 32-bit result by alternating the bits of the operands. Thus, <code>#65535$#0</code> has the 32-bit binary form 101010....10 or 2863311530 decimal, while <code>#0$#65535</code> = 0101....01 binary = 1431655765 decimal, and <code>#255$#255</code> is equivalent to <code>#65535</code>. </blockquote>

Operation 8 returns the interleave of the lower halves of A and B, while operation 9 returns the interleave of the upper halves of A and B. (Should the chip fabrication process allow for it, operation 8½ will, of course, return the interleave of the middle halves of A and B.)

Operations 10 and 11 correspond to INTERCAL's select operator, represented by sqiggle (~). From the INTERCAL manual:

<blockquote> The select operator takes from the first operand whichever bits correspond to 1's in the second operand, and packs these bits to the right in the result. Both operands are automatically padded on the left with zeros. […] For example, <code>#179~#201</code> (binary value 10110011~11001001) selects from the first argument the 8th, 7th, 4th, and 1st from last bits, namely, 1001, which = 9. But <code>#201~#179</code> selects from binary 11001001 the 8th, 6th, 5th, 2nd, and 1st from last bits, giving 10001 = 17. <code>#179~#179</code> has the value 31, while <code>#201~#201</code> has the value 15. </blockquote>

To help understand the select operator, the INTERCAL manual also provides a helpful circuitous diagram.

Use of operations 12 and above is not recommended, unless undefined behavior is required.

How to test

The following example calculations found in the INTERCAL manual should be particularly illuminating.

S A B F
MINGLE16L (8) 0 256 65536
MINGLE16L (8) 65535 0 2863311530
MINGLE16L (8) 0 65535 1431655765
MINGLE16L (8) 255 255 65535
SELECT16 (10) 51 21 5 *
SELECT16 (10) 179 201 9
SELECT16 (10) 201 179 17
SELECT16 (10) 179 179 31
SELECT16 (10) 201 201 15
AND16 (2) 77 4
OR16 (4) 77 32879
XOR16 (6) 77 32875

These test cases are included in the (unfortunately Python and not INTERCAL) test.py file. As these are likely more INTERCAL operations than any sensible person will ever perform, they should be sufficient for testing purposes. However, for curiosity's sake, an extensive set of additional test cases have also been included.

* Not found in the INTERCAL manual.

External hardware

The ALU may be used without external hardware, although seeing the output values may present a challenge. Instead, it is recommended to use a microcontroller of some sort to drive the inputs and read the outputs, as microcontrollers are designed to do. The implementation of the rest of the INTERCAL language is left as an exercise for the reader.

Further reading

The INTERCAL Programming Language Revised Reference Manual by Donald R. Woods and James M. Lyon with revisions by Louis Howell and Eric S. Raymond (can recommend highly enough)

IO

#InputOutputBidirectional
0A0 (address)D0D0
1A1 (address)D1D1
2S0 (selector)D2D2
3S1 (selector)D3D3
4S2 (selector)D4D4
5S3 (selector)D5D5
6/OE (output enable)D6D6
7/WE (write enable)D7D7

Chip location

Controller Mux Mux Mux Mux Mux Mux Mux Mux Mux Mux Analog Mux Mux Mux Mux Mux Mux Mux Mux tt_um_chip_rom (Chip ROM) tt_um_factory_test (Tiny Tapeout Factory Test) tt_um_ieee_LDO (LDO) tt_um_chip_ieee_analog (IEEE Bandgap Reference) tt_um_snn_voice_calculator_mauro_ciccone (snn-voice-calculator) tt_um_hx2003_delay (4 Channel - 32 Tap Programmable Delay with Delay Locked Loop Calibration) tt_um_adxl362_test (tt_um_adxl362_test) tt_um_larsnit_cfar (1D CA/GO/SO CFAR radar detector) tt_um_abeccari_swsynth (Sine Wave Synthesizer) tt_um_dpi_adexp (AdExp DPI Neuron ) tt_um_140oo041_fpu130 (FPU-130) tt_um_blonghi_uart (uart) tt_um_directsgg_mini_proceo_8bit (Mini 8-bit Processor) tt_um_umaece1982_lfsr (Low-Power LFSR-Based Test Pattern Generator) tt_um_deploy_timer (launch deployment timer) tt_um_urish_simon (Simon Says memory game) tt_um_nimelli_kinematic_wave_engine (Kinematic Wave Engine) tt_um_multi_seg_monitor (Multi Segment Monitor) tt_um_UART_TX (project) tt_um_crc8_lfsr (CRC-8 Serial LFSR) tt_um_tinynpu4 (TinyNPU4) tt_um_alu_bns (6-bit multi function ALU ( eldawly_V2) ) tt_um_echoworld424_tpv (Timing-Prediction Test Vehicle) tt_um_gyro_lockin (Laser Gyro Lock-in Readout Core) tt_um_josue_olivos_sar_adc (4-Bit Charge-Redistribution SAR ADC Controller) tt_um_flower (VGA Flower) tt_um_vperumal_l1_fabric (Scalable Banked L1 Memory Fabric for Edge AI) tt_um_preinception_top (Preinception: Simple Compute Accelerator) tt_um_italu (iTALU: Interactive Testable Arithmetic Logic Unit) tt_um_neuron (4-Input Signed Neuron / Perceptron) tt_um_4tap_mac (4-Tap Signed MAC Unit) tt_um_mac_engine (DSP MAC Engine) tt_um_crypto_led_demo (QAMER CryptoUART: Encrypted UART with LED Status) tt_um_layernorm (LayerNorm) tt_um_ez130_8t_mystery (EZ130 8T Mystery Circuit) tt_um_sent2spi (SENT Receiver with SPI Interface) tt_um_llr_hepiarisc (Hepiarisc with SPI flash) tt_um_rebeccargb_vga_pride (VGA Pride) tt_um_hasi_ising (Oscillator Ising Machine) tt_um_c061618g2 (Circuitli C061618G2) tt_um_tiny_dram_pim (Tiny Dual-Channel DRAM-PIM Controller + PU) tt_um_Tbilisi_CORDIC_Engine (Tbilisi CORDIC Engine) tt_um_rahulmascarenhas_folded_nn (Frozen ternary backbone + loadable head) tt_um_miniMAC (miniMAC_IHP26b) tt_um_rumcajs (IEEE DOORSH) tt_um_sg13g2_mystery (SG13G2 Mystery Circuit) tt_um_ULSR88 (ULSR demo) tt_um_ez130_7t_mystery (EZ130 7T Mystery Circuit) tt_um_tinyopt4 (ieee_tt_tinyopt4) tt_um_vga_example (IEEE VGA Animated Beach) tt_um_hyphen133_drone_detection (IEEE Acoustic Drone Detector) tt_um_nuatlabs_fifo_pwm (Async FIFO with CDC + PWM Peripheral) tt_um_nuatlabs_uart (8N1 UART Transceiver) tt_um_eeg_threshold_detector (IEEE Digital EEG Threshold Event Detector) tt_um_smart_traffic (Smart Traffic Light Controller) tt_um_94442024_mini_cpu (Mini 8-bit Accumulator CPU) tt_um_wokwi_475369131246576641 (IEEE_UPB_TT_1) tt_um_aion (AION) tt_um_rebeccargb_hardware_utf8 (Hardware UTF Encoder/Decoder) tt_um_rebeccargb_universal_decoder (Universal Binary to Segment Decoder) tt_um_rebeccargb_intercal_alu (INTERCAL ALU) tt_um_flappy_bird (IEEE Flappy Bird VGA Game) tt_um_oryan01_alu (ALU CASS PUCV) tt_um_S4xU4 (S4xU4) tt_um_vga_ca (Space CA) tt_um_llr_simplenpu (simple SPI flash streaming NPU) tt_um_pucv_pspwm (3LFCC PS-PWM Modulator) tt_um_yuri_fpga (Tiny FPGA) tt_um_mikailgedik_inverted_inverters (Inverted inverters) tt_um_esauqch_hamming74 (Hamming(7,4) encoder/decoder (IEEE)) tt_um_hackin7_analog_experiments (TinyAnalogExperiments) tt_um_snake (snake game) tt_um_mini_kraken (Kraken IO Subprocessor) tt_um_fabien_pio (AstraPIO) tt_um_chiplab (ChipLab) tt_um_wokwi_475490677474407425 (Tiny_Divider) tt_um_c061618g2tr (Circuitli C061618G2TR) tt_um_catalinlazar_nanopio (nanoPIO) tt_um_catalinlazar_uart_spi_i2c_bridge (UART-SPI-I2C Bridge) tt_um_enzonappi_sent_i2c (SENT to I2C bridge) tt_um_kush1434_proof (Proof) tt_um_schwallsunk_signal_discriminator (Highspeed voltage discriminator) tt_um_tiarinix_ttihp_verilog_template (8-bit educational SAP-style CPU) tt_um_vga_glyph_mode (BOOTCAMP) tt_um_GiulioGirelli_packet_processor (Configurable Low-Latency Match-Action Packet Processor) tt_um_vga_tictactoe (Tic Tac Toe) tt_um_vga_dvd_player (DVD player) tt_um_clea_katseye_rain (KATSEYE) tt_um_romd_uart_hello (UART Hello World) tt_um_vga_snake (CDM PYTHON GAME) tt_um_vga_slot_machine (tt_um_vga_slot_machine) tt_um_jet_seq8b (SEQ8 Programmable Sequencer) tt_um_kibo_leak_inspect (KIBO Leak-Inspection Target Controller (VGA)) tt_um_endless_runner (Endless Runner) tt_um_omega_infinity_kaoru (OMEGA INFINITY KAORU 3D Metal Grid Processor) tt_um_nikleberg_mixer (Mixer) tt_um_lahnb_sgdma (TinyDMA: A Descriptor-Based Dual-PSRAM Memory Mover) tt_um_gstj_lockin (Digital IQ Lock-in (IEEE)) tt_um_benpayne_ps2_decoder (PS/2 Keyboard Decoder for 68k) tt_um_cass_s_ui_neuron_lif (Neurona LIF con Aprendizaje STDP Dinamico (IEEE)) tt_um_vga_glyph_mode_CDM_Matrix (CDM Matrix) tt_um_qd39l_xor_stream (Fixed-ROM XOR Stream Engine) tt_um_conv3x3 (3x3 Clock Rate Streaming Input Convolution Engine) tt_um_mc14500b_soc_extended (MC14500B Extended 1-bit Microcontroller SoC) tt_um_vga_hypno_spiral (tt_um_vga_hypno_spiral) tt_um_mattizen_morse_tree (Morse Tree LED Decoder) tt_um_CDM (Colegio de Muntinlupa DVD-like Display) tt_um_romd_uart_loader (UART SPI RAM Loader) tt_um_TscherterJunior_stapel_geraet (stapel gerät) tt_um_das2225_dna_accel (DNA_Accel) tt_um_tinysoc (TinySoC) tt_um_barrel_shifter (Barrel Shifter) tt_um_approx_mac_coprocessor (Approximate DSP: Time-Multiplexed MAC Coprocessor) tt_um_joesagents_market_split_oracle (Market-split oracle) tt_um_mgpauly1458_ringmeter (Ring oscillator frequency meter) tt_um_pettit_prism_lite (PRISM with Risc-V (TinyQV) SoC) tt_um_workshop_cpu (IEEE Workshop Simple CPU) tt_um_algofoogle_analog_junk (Simple comparator + 2 DACs analog layout in a 1x1 tile) tt_um_lkhanh_cordic (TinyQV SoC (Dual Memory Backend)) tt_um_4x4npu (4x4NPU: Dual-Lane INT4 Neural Accelerator) tt_um_abiaselli_izh_bridge_3x2 (Izhikevich event bridge (4 contexts)) tt_um_fabulous_ihp_26b (Tiny FABulous FPGA) tt_um_zanderivo_voronoi (Four-Metric VGA Nearest-Prototype Visualizer)