Convert an 8bit number to hex in z80 assembler - hex

I am writing a game for the ZX Spectrum using z80 and have a bit of a problem.
I have manipulated a routine to convert a number held in the “a” register to a hex value held in “de”. I’m not sure of how to convert the other way, EG pass in a hex value in de and convert this to decimal held in “a”.
NB: The following routine converts the input to the ascii values that represent the values 0 through to F. EG if a = 255 then d =70 and e = 70 as “F” is ascii value 70.
NumToHex ld c, a ; a = number to convert
call Num1
ld d, a
ld a, c
call Num2
ld e, a
ret ; return with hex number in de
Num1 rra
rra
rra
rra
Num2 or $F0
daa
add a, $A0
adc a, $40 ; Ascii hex at this point (0 to F)
ret
Can anyone advise on a solution to work this in reverse or offer a better solution?

This code takes DE has a hexadecimal number in ASCII and converts it to binary in A. It assumes that DE is a valid hexadecimal number and uses uppercase 'A' through 'F'. It will fail if lowercase letters are used or any ASCII character outside of '0' .. '9' and 'A' .. 'F'.
HexToNum ld a,d
call Hex1
add a,a
add a,a
add a,a
add a,a
ld d,a
ld a,e
call Hex1
or d
ret
Hex1 sub a,'0'
cp 10
ret c
sub a,'A'-'0'-10
ret
Update: Have now tested code and fixed bug in handling of 'A' .. 'F' case in Hex1.
Update: Using "add a,a" which is faster than "sla a". Note that if speed is a concern both conversions can be done much more quickly with lookup tables.

Related

Rearranging a vector in parallel for fast performance

I have a vector whose length can go up to about a few million or more.
If I say the vector is vec = [a1 a2 ...b1 b2 ... c1 c2 ...d1 d2 ...]
I need to rearrange vec to new_vec = [a1 b1 c1 d1 a2 b2 c2 d2 ...] .
If viewed as a matrix of column vectors, then this could be viewed as a transpose, but I do not have a two dimensional vector. I understand how to do it on a sequential computer. That is very simple.
But I am not sure how to do this on a multiple processor cluster or on a GPU, or even if this would be feasible on parallel machines. Memory seems to be the obvious bottleneck. If there are any algorithms or any architecture specific optimizations that I can use, please let me know.
Edit: More information below.
The code structure is:
subroutine reorder(vec,parameter)
real(kind = 8),dimension(parameter%length), intent(inout) :: vec
real(kind = 8),dimension(parameter%length) :: temp
type(param) :: parameter !just a struct holding certain constant parameters
integer :: i,j,k,q1,q2,q3,nn1,n1,n2,nn2
i1 = parameter%len1 !lengths of sub-vectors in each direction
i2 = parameter%len2 !the multiplication of the 3 gives the
!overall length of vec
i3 = parameter%len3
temp = vec
n1 = i2*i1
n2 = i2*i3
do k = 1, i3
q1 = n1*(k-1)
q2 = i2*(k-1)
do j = 1, i2
q3 = i1*(j-1)
do i = 1, i1
nn1 = q1+q3+i
nn2 = q2+j+n2*(i-1)
vec(nn2) = temp(nn1)
end do
end do
end do
end subroutine reorder
Therefore the code aims to reorder the elements of the vector according to the rule. As you can see as the length of the vector becomes very large, a significant time is spent in this routine.
This routine is called in a main routine multiple times. A cartesian decomposition produces a cartesian 3D arrangement of ranks in the beginning and each rank calls this subroutine when a reordering of the elements is required for its own next subroutine call.The cartesian communicator subroutine is shown in the skeleton below:
subroutine cartesian_comm(ndim,comm_cart,comm_one_d,coord_cart)
use mpi
implicit none
integer, dimension(:), intent(in) :: ndim
integer, intent(out) :: comm_cart
integer, dimension(:), pointer :: comm_one_d, coord_cart
logical, dimension(size(ndim)) :: period, remain
integer :: dim,code, i, rank
!creating the cartesian communicator
dim = 3
allocate(comm_one_d(dim),coord_cart(dim))
period = .FALSE.
call MPI_CART_CREATE(MPI_COMM_WORLD, dim, ndim, period, .FALSE., comm_cart, code)
call MPI_COMM_RANK(comm_cart, rank, code)
call MPI_CART_COORDS(comm_cart, rank, dim, coord_cart, code)
!Creating sub-communicator for each direction
do i = 1, dim
remain = .FALSE.
remain(i) = .TRUE.
call MPI_CART_SUB(comm_cart, remain, comm_one_d(i), code)
end do
end subroutine cartesian_comm
And it is called in the main function as follows:
Program main
!initialize some stuff and intialize all the required variables
! ndim is the number of processes the program is called
! with "mpirun -np 8 ./exec" would mean ndim is cuberoot of 8,
! and therefore 2 for the 3D case. It is always made sure that
! np is a cube(or square for 2D) while calling the program
call cartesian_comm(ndim,comm_cart,comm_one_d,coord_cart)
do while (t<tend-1D-8) !start time loop
t = t + dt
!do some computations get the vector "vec" for
!each rank separately (different and independent in each rank)
call reorder(vec,parameter) ! all ranks call this subroutine
!do some computations here with the new reordered vec
end do !end time loop
!do other stuff (unrelated to reorder but use the "vec" vector) here
end Program main
I would like to know if there is a better way to do this in a multiprocessor cluster, or how I could proceed in the case of a GPU.

How to convert a group of Hexadecimal to Decimal (Visual Studio )

I want to retrieve like in Pic2, the values in Decimal. ( hardcoded for visual understanding)
This is the codes to convert Hex to Dec for 16 bit:
string H;
int D;
H = txtHex.Text;
D = Convert.ToInt16(H, 16);
txtDec.Text = Convert.ToString(D);
however it doesn't work for a whole group
So the hex you are looking at does not refer to a decimal number. If it did refer to a single number that number would be far too large to store in any integral type. It might actually be too large to store in floating point types.
That hex you are looking at represents the binary data of a file. Each set of two characters represents one byte (because 16^2 = 2^8).
Take each pair of hex characters and convert it to a value between 0 and 255. You can accomplish this easily by converting each character to its numerical value. In case you don't have a complete understanding of what hex is, here's a map.
'0' = 0
'1' = 1
'2' = 2
'3' = 3
'4' = 4
'5' = 5
'6' = 6
'7' = 7
'8' = 8
'9' = 9
'A' = 10
'B' = 11
'C' = 12
'D' = 13
'E' = 14
'F' = 15
If the character on the left evaluates to n and the character on the right evaluates to m then the decimal value of the hex pair is (n x 16) + m.
You can use this method to get your values between 0 and 255. You then need to store each value in an unsigned char (this is a C/C++/ObjC term - I have no idea what the C# or VBA equivalent is, sorry). You then concatenate these unsigned char's to create the binary of the file. It is very important that you use an 8 bit type to store these values. You should not store these values in 16 bit integers, as you do above, or you will get corrupted data.
I don't know what you're meant to output in your program but this is how you get the data. If you provide a little more information I can probably help you use this binary.
You will need to split the contents into separate hex-number pairs ("B9", "D1" and so on). Then you can convert each into their "byte" value and add it to a result list.
Something like this, although you may need to adjust the "Split" (now it uses single spaces, returns, newlines and tabs as separator):
var byteList = new List<byte>();
foreach(var bytestring in txtHex.Text.Split(new[] {' ', '\r', '\n', '\t'},
StringSplitOptions.RemoveEmptyEntries))
{
byteList.Add(Convert.ToByte(bytestring, 16));
}
byte[] bytes = byteList.ToArray(); // further processing usually needs a byte-array instead of a List<byte>
What you then do with those "bytes" is up to you.

How to store the ASCII value in a character (Ada 83 Only)

How do I store the ascii value of an integer (say 33) in a character. I want something like this in Ada83, not 95
C: Code
char c = 10;
char *k = &c;
strncat (des, k, 1);
printf("%s",des);
Thank you!!
C : Character := Character'Val(10);
or
C : Character := ASCII.LF;
The first works in all versions of Ada. The second one was the standard way in Ada 83; it is now obsolescent. The newer way is
C : Character := Ada.Characters.Latin_1.LF;
More information: In Ada, Character is an enumeration type, not an integer type. Therefore, you can't assign an integer to it directly. The 'Val attribute is the Ada way to convert an integer to an enumeration; Enum_Type'Val(N) means "the Nth enumeration literal defined for the enumeration type, 0-relative". To go the other way, Enum_Type'Pos(E) returns the integer corresponding to the position of E in the enumeration list.

About pointers and ASCII code

im learning more about c language and i have 1 doubt about 1 code that i have seen.
main(){
int i = (65*256+66)*256+67;
int* pi;
char* pc;
pi = &i;
pc = (char*)pi;
printf("%c %c %c \n", *pc, *(pc+1), *(pc+2));
}
Output is: C B A
I know that ASCII code of A is 65, B is 66, and C is 67 but the variable i is none of them.
If i put variable i=65, the output is just A and dont show B or C, why?
And i would like to know why this code have that output. Thanks for any help.
The line
int i = (65*256+66)*256+67;
turns i into the following
00000000 01000001 01000010 01000011
int = 4 bytes or 4 groups of 8 bits
char = 1 byte or 1 group of 8 bits.
What happens is that a char pointer is used to point to a subset of the original int bits.
At first the pointer points to the 8 least significant bits (the group to the right).
And the letter C is printed. Then, the pointer it self is incremented by 1 which makes it point to the next group of 8 bits in the memory which happens to be B. And once more for the A.
*256 means left shift by 8 bit (1 byte) so the line
int i = (65*256+66)*256+67;
actually put A,B,C on 3 adjacent bytes in memory
then pi pointer made point to the address of integer i, then same address down cast to char pointer pc, so pc actually hold the address to a byte that contains 'A', and of course if you add 1 and 2 to the address that means the adjacent 'B' and 'C' get pointed to and print out.
EDIT: just to clarify a bit more int is 32 bit long but char is 8 bit, that's why u need a char pointer to represent an address valid for 8 bit long.
Characters are stored as bytes, as you probably know. The initializing of the variable 'i' has the following meaning:
65*256 // store 65 ('A') and left shift it by 8 byte (= '*256')
(65*256+66)*256 // add 66 ('B') and shift the whole thing again
(65*256+66)*256+67 // add 67 ('C')
'pi' is initialized as a INT pointer to 'i'
'pc' is initialized as a CHAR pointer to 'pi'
So 'pc' then holds the address of the beginning of the 3 bytes stored in 'i', which holds 'A'.
By adding 1 and 2 to the address in pc, you get the second and third bytes (containing 'B' and 'C'), as follows:
printf("%c %c %c \n", *pc, *(pc+1), *(pc+2));
Working on the bits here ;D

Z80 Register Endianness

Considering this sample code:
ZilogZ80A cpu = new ZilogZ80A();
cpu.GeneralRegisters.H.FromUInt(229);
cpu.GeneralRegisters.L.FromUInt(90);
Console.WriteLine("H : " + cpu.GeneralRegisters.H.ToString());
Console.WriteLine("L : " + cpu.GeneralRegisters.L.ToString());
Console.WriteLine("HL: " + cpu.GeneralRegisters.HL.ToString());
Console.WriteLine("Load 23268 (0x5AE4) into register HL...");
cpu.GeneralRegisters.HL.FromUInt(23268);
Console.WriteLine("H : " + cpu.GeneralRegisters.H.ToString());
Console.WriteLine("L : " + cpu.GeneralRegisters.L.ToString());
Console.WriteLine("HL: " + cpu.GeneralRegisters.HL.ToString());
Which is doing the following:
Load 229 (decimal) into register H
Load 90 (decimal) into register L
Print out the values (hex, binary MSB, decimal) of the H, L and HL registers
Load 23268 (decimal) into register HL
Print out the values of the H, L and HL registers again.
Sample output:
H : 08-bit length register (#45653674): 0x00E5 | MSB 0b11100101 | 229
L : 08-bit length register (#41149443): 0x005A | MSB 0b01011010 | 90
HL: 16-bit length register (#39785641): 0x5AE5 | MSB 0b01011010 11100101 | 23269
Load 23268 (0x5AE4 into register HL...
H : 08-bit length register (#45653674): 0x00E4 | MSB 0b11100100 | 228
L : 08-bit length register (#41149443): 0x005A | MSB 0b01011010 | 90
HL: 16-bit length register (#39785641): 0x5AE4 | MSB 0b01011010 11100100 | 23268
Now for the questions:
Are the above assumptions (and sample output) on how the registers function correct?
Do the other register pairs (AF, BC, DE) function the exact same way?
If the answer to 1. and 2. is yes, why is the Z80 then considered little endian? When the HL register contents gets written to memory the L byte goes first, but (when reading them sequentially afterwards the bytes surely are in big endian order)?
Yes — HL is composed of H as the most significant byte, L as the least. If you perform a 16-bit operation like ADD HL,BC then carry from the top bit of L+C will flow into the computation of H+B. All the register pairs are alike in this regard.
That's because the logical order things are written in isn't related to endianess. E.g. in C you don't have to write 0x0001 on some platforms to equal 0x0100 on others. When writing, you write the most significant first.
The z80 is little endian because if you were to store HL to memory, L would be written a byte before H. If you were to read, L would be read from the address before H.
ld hl, $1234
ld ($fc00), hl
At this point, H = $12, L = $34, as your code suggests. The byte at $fc00 = $34, and the byte at $fc01 = $12.
So if you subsequently do:
ld hl, $5678
ld ($fc02), hl
($fc00) = $34, ($fc01) = $12, ($fc02) = $78, and ($fc03) = $56. So reading byte by byte from $fc00, memory would be $34127856, instead of $12345678, because Z80 is little endian.

Resources