Why another Hardware Processor?
Hardware description languages are good for particular problems (e.g parallel memory calculation jobs). But it is tough to handle sequential execution problems with them. For such problems the sequential execution of a programm often fits well. A standard solution would be to use a Microcontroller Core (e.g. from Opencores written in VHDL). To programm this Microcontroller often the C programming language is used. The C code is converted to Assembler and the Assembler code is then loaded into the Microcontroller. To accomplish such a task you at least need a C programming environment and a VHDL programming enviroment and you need a chain between them create and load the Assembler. What if you could write your Microcontroller Code in the same environment where you describe your hardware. This is where the Python Hardware Processor together with Myhdl fits in. So the idea was to create a Python Hardware Processor that supports just enougth of the python language to handle sequential execution problems. Parallel array processing jobs and comparable, are then implemented in the hardware description language where they normaly nicely fit and perform well.
Download pyCPU
You can get the curent development files at:
http://sourceforge.net/projects/pycpu/files/
Explaning the Files on sourceforge:
RS232_Norbo.py …..Implements the RS232 Receiver/Transmitter Unit
MakeProcessorBytecode.py …..Generates the Code for the Cpu from the Python code.
pyCPU.py …..Implennts the Complete CPU and uses RS232_Norbo.py and MakeProcessorBytecode.py for this
Using the UART unit of the pyCPU
The pyCPU has a UART unit now.
The Baudrate of the UART unit is set in the Myhdl code. The unit does a 8 bit transmission with no parity and one Stopbit. The usage of the now tightly integrated UART unit is demonstrated in the code below:
PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3, \ 'RS232Data':4,'RS232_READ_ADDRESS':5,'RS232_RECEIVE_ADDRESS':6,'RS232_WRITEBUFFER_FULL':7 } def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT,RS232Data,RS232_READ_ADDRESS,RS232_RECEIVE_ADDRESS,RS232_WRITEBUFFER_FULL x=0 RS232_READ_ADDRESS=0 while 1: ##### RS232 Transmitting ###### # Only write something to the Transmit buffer if not full if not RS232_WRITEBUFFER_FULL: # Write the value of x to the RS232 Transmit # buffer if something is in the Transmit-Buffer, sending # is started automatically RS232Data=x x=x+1 ##### RS232 Receiving ###### # Wait until a byte is received in the Receive-Buffer if RS232_READ_ADDRESS!=RS232_RECEIVE_ADDRESS: # Read data from RS232 receive buffer at the RS232_READ_ADDRESS PORTD_OUT=RS232Data # Set the Read address the the current received RS232_READ_ADDRESS=RS232_RECEIVE_ADDRESS
Advantages:
- Easier access to RS232 than in most Microcontrollers today
- Receive-/ and Transmit-Buffer (Buffersize is set in the hardware description)
Disadvantages:
- No interrupt
- No dynamic baudrate configuration
- Only 8 Bit Mode, no parity bit and 1 Stopbit
- If you want more options you have to upgrade the hardware description
Supported Python Code
- Int’s (with … bits, depends on how many you what to instanciate on the hardware), no other python types only plane ints (it means no list,dict,tuple,etc..)
- If and while (comparisions with <,>, >=, ⇐,!=,== )
- Assignments to globals or local varibles from const, globals or defined local variables
- Operators: +. -, ^ ,~, |, & ,«,»
- Simple Digital IOs access for Hardware PORTS (implemented through a distinct global varible)
- Function calls (with: consts, globals, or local vars as argument and one intager as return value), no default arguments, no keyword arguments,no functions or functioncalls as arguments
- nested while loops up to CONST_LOOP_DEPTH (Constant default value = 4)
- up to MAX_NUMBER_FUNCTION_ARGUMENTS (Constant default value = 10) arguments
- up to CONST_PC_STACK_DEPTH (Constant default value=5) number of nested function calls
- up to VAR_MEM_DEPTH (Constant default value=20) local variables
Simple pyCPU Programcode example
The Following is a simple program for the pyCPU (Python Hardware Processor). Keep in mind that the Databitwitdth is limited to a constant factor given to the Myhdl description.
PREDEFINED_IO_ADDRESSES={'PORTA_IN':0,'PORTB_IN':1,'PORTC_OUT':2,'PORTD_OUT':3 } def busywait(time): x=0 while x<100: td=0 x=x+1 while td<100: td=td+1 ss=0 while ss<time: ss=ss+1 def CPU_main(): global PORTA_IN,PORTB_IN,PORTC_OUT,PORTD_OUT x=0 while 1: PORTD_OUT=PORTD_OUT^16 busywait(20) if (PORTB_IN & 0x01)==1: PORTD_OUT=PORTD_OUT|0x20 else: PORTD_OUT=PORTD_OUT&0xdf
To get a little insight you can use the dis python module to show the bytecode instructions. The instructions for the function CPU_main are shown below .
import dis dis.dis(CPU_main) 3 0 LOAD_CONST 1 (0) 3 STORE_FAST 0 (x) 4 6 SETUP_LOOP 62 (to 71) 5 >> 9 LOAD_GLOBAL 0 (PORTD_OUT) 12 LOAD_CONST 2 (16) 15 BINARY_XOR 16 STORE_GLOBAL 0 (PORTD_OUT) 6 19 LOAD_GLOBAL 1 (busywait) 22 LOAD_CONST 3 (20) 25 CALL_FUNCTION 1 28 POP_TOP 7 29 LOAD_GLOBAL 2 (PORTB_IN) 32 LOAD_CONST 4 (1) 35 BINARY_AND 36 LOAD_CONST 4 (1) 39 COMPARE_OP 2 (==) 42 POP_JUMP_IF_FALSE 58 8 45 LOAD_GLOBAL 0 (PORTD_OUT) 48 LOAD_CONST 5 (32) 51 BINARY_OR 52 STORE_GLOBAL 0 (PORTD_OUT) 55 JUMP_ABSOLUTE 9 10 >> 58 LOAD_GLOBAL 0 (PORTD_OUT) 61 LOAD_CONST 6 (223) 64 BINARY_AND 65 STORE_GLOBAL 0 (PORTD_OUT) 68 JUMP_ABSOLUTE 9 >> 71 LOAD_CONST 0 (None) 74 RETURN_VALUE
Python Hardware Processor -> pyCPU Intro
The Python Hardware Processsor is a implementation of a Hardware CPU in Myhdl. The CPU can directly execute something very similar to python bytecode (but only a very restricted instruction set). The Programm code for the CPU can be written directly in python (very restricted parts of python). This code is then converted by a small python programm to this restricted python bytecode. Since the hardware description is also in python, the slightly modified bytecode an then automatically loaded into the CPU design.
Most “bytecode” instructions are executed in the Hardware CPU with one instruction per cycle. If you have enought hardware available you can simply instantiate more cores on an FPGA with different Programmcode to make them run in parallel.
Due to the python nature of Myhdl and the Python Hardware Prozessor written with it, it
allows you, to write a Programm for the prozessor, to simulate the Hardware Processor
and to convert the Processor to a valid hardware description (VHDL or Verilog) inside
a single python environment.