News:

The Savage///Circuits website has been upgraded to a more efficient theme.

Main Menu

Assembly?

Started by JKnightandKARR, Nov 02, 2025, 01:54 PM

Previous topic - Next topic

Chris Savage

Quote from: JKnightandKARR on Nov 10, 2025, 06:55 AMI am just getting to that part in the cardiac book actually. Was reading it yesterday at work and stoped in that area.

I should have said that ALL the registers are important to understand. Many assembly instructions have multiple address modes as well. I tend to think of the program counter from the context of the Z80:

QuoteThe Z80 program counter (PC) is a 16-bit register that holds the memory address of the next instruction to be fetched and executed by the CPU. After fetching an instruction, the PC is automatically incremented, and for jump or call instructions, it is directly loaded with the new address, overriding the increment. The Z80 does not allow direct modification of the PC with a standard instruction; instead, a new address can be pushed onto the stack and then the stack's top value can be retrieved using a RET instruction, which loads it into the PC.

Of course, you could just do a JP to an address to force load it as well. But I think it demonstrates the power of the PC.

                    Bringing concepts to life through engineering.

MicroNut

#31
Once again I'm a little late to the party. My assembly code experience was learning 6502 assembly in college. Penn State at the time thought it would be THE computer chip of the future. :) I also had a course in microcoding, which is learning the algorithms involved in taking the adders and shifters of a cpu and make them do higher level math.  I then got a ZX81 and to bypass all the limitations of Basic I delved into Z80. I also used Z80 at one of my jobs.

The book I was working on was my attempt of learning how the internal logic of the Z80 works. It stalled out when I got to the PLA (Programming Logic Array) which was a lot more complex than I bargained for. Right now I'm chasing another squirrel, learning the Propeller 2 and I would also like to get into the assembly code. So, we could share notes :)

Chris is right that the P1 and P2 aren't the same as Z80 and 6502. One thing it does is self modifying code which is a great way of conditional redirecting but gives me nightmares! Also to use assembly wisely one must know the hardware they are using. So I'm learning more about streaming and smart pins to work with the P2.

If you plan on looking into the Z80 assembler on a ZX81 an emulator that works well can be found at
https://sourceforge.net/projects/eightyone-sinclair-emulator/
and the best forum for advice is www.sinclairzxworld.com
Always looking to the stars.

Chris Savage

#32
Quote from: MicroNut on Nov 10, 2025, 12:41 PMOnce again I'm a little late to the party. My assembly code experience was learning 6502 assembly in college.

I wouldn't say you're late to the party. This party is just getting started!  8)

Quote from: MicroNut on Nov 10, 2025, 12:41 PMRight now I'm chasing another squirrel, learning the Propeller 2 and I would also like to get into the assembly code. So, we could share notes :) Chris is right that the P1 and P2 aren't the same as Z80 and 6502.

Yeah, there's the whole CPU VS MCU VS SBC thing, but then, just among MCUs, the P1 / P2 are multi-core, adding a level of complexity that makes it more interesting for those trying to learn on that platform. then of course there's the lack of educational resources for the P2 and well, I would definitely start with something simpler.

For those reading this and wondering what all the acronyms are:

CPU - Central Processing Unit - The brains of a computer system. RAM, ROM, I/O and interface circuitry are in addition to the CPU in a computer system. See my Z80 Control Board for an example.

MCU - Micro-Controller Unit - A complete system that includes the CPU, RAM, ROM, I/O, etc. Usually requires an external clock and voltage regulation, but otherwise quite complete for digital control systems. An Arduino is a good example of an MCU.

SBC - Sing-Board Computer - A Raspberry Pi is a good example of an SBC. These systems run an entire O/S and, while they may be able to control much the same digital systems as an MCU, there is a lot of overhead, especially from a software standpoint.

Another little note for future readers...the 6502 and Z80 are both 8-bit CPUs (as indicated by their 8-bit data bus), however, the Z80 can directly access 16-bit registers by using two registers. This gives it direct 16-bit data manipulation. The Z80 also includes two 16-bit index registers.

...we now return to our original educational thread, already in progress...

                    Bringing concepts to life through engineering.

JKnightandKARR

#33
Quote from: Chris Savage on Nov 10, 2025, 09:08 AMI should have said that ALL the registers are important to understand. Many assembly instructions have multiple address modes as well. I tend to think of the program counter from the context of the Z80:
That goes without saying. I may not know much, but I do know they are all there for a good reason.9k and a specific job.

Quote from: Chris Savage on Nov 10, 2025, 09:08 AMThe Z80 program counter (PC) is a 16-bit register that holds the memory address of the next instruction to be fetched and executed by the CPU. After fetching an instruction, the PC is automatically incremented, and for jump or call instructions, it is directly loaded with the new address, overriding the increment. The Z80 does not allow direct modification of the PC with a standard instruction; instead, a new address can be pushed onto the stack and then the stack's top value can be retrieved using a RET instruction, which loads it into the PC.

Of course, you could just do a JP to an address to force load it as well. But I think it demonstrates the power of the PC.[/quote]
I think I understand, but it's still a little blurry at the moment... Could be that I am pretty tired right now too...

Quote from: MicroNut on Nov 10, 2025, 12:41 PMOnce again I'm a little late to the party. My assembly code experience was learning 6502 assembly in college. Penn State at the time thought it would be THE computer chip of the future. :) I also had a course in microcoding, which is learning the algorithms involved in taking the adders and shifters of a cpu and make them do higher level math.  I then got a ZX81 and to bypass all the limitations of Basic I delved into Z80. I also used Z80 at one of my jobs.

The book I was working on was my attempt of learning how the internal logic of the Z80 works. It stalled out when I got to the PLA (Programming Logic Array) which was a lot more complex than I bargained for. Right now I'm chasing another squirrel, learning the Propeller 2 and I would also like to get into the assembly code. So, we could share notes :)

Chris is right that the P1 and P2 aren't the same as Z80 and 6502. One thing it does is self modifying code which is a great way of conditional redirecting but gives me nightmares! Also to use assembly wisely one must know the hardware they are using. So I'm learning more about streaming and smart pins to work with the P2.

If you plan on looking into the Z80 assembler on a ZX81 an emulator that works well can be found at
https://sourceforge.net/projects/eightyone-sinclair-emulator/
and the best forum for advice is www.sinclairzxworld.com
Oh trust me, I didn't expect the P1/P2 to be the same, just somewhat similar.  Learning the P1/P2 assem is a goal, though at moment, I am trying to figure out how to understand the P2 Spin....  I also wanna learn other stuff, such as Arduino, stuff for Raspberry Pi's, and the PicoMite.  Wonder for quite a while if putting too much on the fire at the same time??

I used to understand assembly on Z80 very well... but many years of not using any of it, I've forgotten it ALL.... I really need to get my desk done, so I can get back into it all...  I've even forgotten some of the BS2/P1 files I've made... well, somewhat, little studying and I got it for the most part.


Chris Savage

#34
Wait until you learn about the Stack Pointer (SP), and the difference between the SP on the 6502 (which grows up in memory) VS the SP on the Z80 (which grows down in memory). Okay, now I'm just throwing fuel on the fire.  :-X

Sorry about that!  ::)  I just get so excited talking about CPUs based on Von Neumann architecture!  :-[

                    Bringing concepts to life through engineering.

JKnightandKARR

#35
Quote from: Chris Savage on Nov 11, 2025, 09:03 AMWait until you learn about the Stack Pointer (SP), and the difference between the SP on the 6502 (which grows up in memory) VS the SP on the Z80 (which grows down in memory). Okay, now I'm just throwing fuel on the fire.  :-X

Sorry about that!  ::)  I just get so excited talking about CPUs based on Von Neumann architecture!  :-[
Lol, you're ok.  I just got waaaaaay tired, think blood sugar was high and/or just very tired. Either way, I need to reread stuff and retype my reply.

Edit: If I understand the PC correctly, It stores the memory location of the instructions to be executed, kinda like some lines of code are on screens when working on programs, NOT the ones from the full list of all avail. instructions from the CPU/MCU. EX:
10
20
30
etc,,,
Yes?

JKnightandKARR

I've edited the above post from last night, after being able to understand what was being said.

Chris Savage

#37
Quote from: JKnightandKARR on Nov 11, 2025, 10:41 AMEdit: If I understand the PC correctly, It stores the memory location of the instructions to be executed, kinda like some lines of code are on screens when working on programs, NOT the ones from the full list of all avail. instructions from the CPU/MCU. EX:
10
20
30
etc,,,
Yes?

Line numbers like that are used in high-level languages like BASIC. This is because each BASIC instruction actually takes up many low-level machine instructions within the BASIC interpreter.

In assembly language, labels are used in place of actual memory locations that the PC holds. For example, $0300. So if my Z80 program starts at location $0100, I might have something like this:

    .ORG $0300
INITIO    LD A,$00
    OUT (LATCH),A
    LD A,(IODATA)
    OUT (CONTROL),A
    LD A,$00
    OUT (PORTB),A
    OUT (PORTC),A
    RET
IODATA    .BYTE $90            ;INIT DATA
    LD HL,LCDDATA
IOLOOP    CALL CHKBUSY
    LD A,(HL)
    OR A
    RET Z
    OUT (LCDI),A
    INC HL
    JP IOLOOP
LCDDATA    .BYTE $38,$08,$01,$06,$0C,$00    ;INIT DATA
    CALL CHKBUSY
    LD HL,CGDATA
    LD B,$10            ;BYTE COUNT
    LD C,$40            ;CG RAM ADDRESS
    LD A,C
    OUT (LCDI),A
    CALL CHKBUSY
    LD A,(HL)
    OUT (LCDD),A
    INC HL
    DEC B
    RET Z
    INC C
    LD A,C
    OUT (LCDI),A
    JP $0333
    .BYTE $11,$00,$04,$00,$11,$0E,$00,$00    ;CHARACTER 1 DATA
    .BYTE $11,$00,$04,$00,$0E,$11,$00,$00    ;CHARACTER 2 DATA
KNIGHT    LD HL,KDATA
    CALL PRINT
    RET
KDATA    .BYTE $0C,"PROGRAMMING COPYRIGHT 1994 CHRIS SAVAGE",$07,$00
RAMTEST    CALL LFEED
    LD HL,RAMDAT1
    CALL PRINT
    LD HL,RAMBOT
    LD BC,$0001
RAMLOOP    LD D,(HL)
    LD E,$AA            ;BIT PATTERN 1
    LD (HL),E
    LD A,(HL)
    CP E
    JP NZ,RAMFAIL
    LD E,$55            ;BIT PATTERN 2
    LD (HL),E
    LD A,(HL)
    CP E
    JP NZ,RAMFAIL
    LD (HL),D            ;RESTORE OLD DATA
    ADD HL,BC
    JP C,RAMPASS
    JP RAMLOOP
RAMPASS    SCF
    CCF
    LD BC,$8000
    SBC HL,BC
    LD ($A100),HL
    CALL DECIMAL
    LD HL,RAMDAT2
    CALL PRINT
    LD D,$08
    CALL DELAY3
    RET
RAMFAIL    CALL LFEED
    LD ($8100),HL
    LD HL,RAMDAT3
    CALL PRINT
    LD HL,($8100)
    LD ($A100),HL
    CALL DECIMAL
    LD HL,RAMDAT4
    CALL PRINT
    LD HL,($8100)
    LD ($A100),HL
    CALL HEX
    LD HL,RAMDAT5
    CALL PRINT
    DI
    JP $03F0            ;LOOP FOREVER (HALT)
RAMDAT1    .BYTE "TESTING RAM...",$00
RAMDAT2    .BYTE $20,"BYTES PASSED.",$00
RAMDAT3    .BYTE "RAM FAILURE AT LOCATION ",$00
RAMDAT4    .BYTE "  ($",$00
RAMDAT5    .BYTE ")",$00,$00
INITVAR    LD A,$00
    LD ($8000),A
    LD ($8001),A
    LD ($8002),A
    LD ($8008),A
    LD ($8009),A
    LD A,$FF
    LD ($8002),A
    LD HL,$0200
    LD ($8003),HL
    LD A,$06
    LD ($8005),A
    LD ($8006),A
    RET

Most older compilers make two passes when compiling...the first usually calculates the addresses for the labels, and the second converts the mnemonics into machine code.

                    Bringing concepts to life through engineering.

JKnightandKARR

Quote from: Chris Savage on Nov 11, 2025, 02:28 PM
Quote from: JKnightandKARR on Nov 11, 2025, 10:41 AMEdit: If I understand the PC correctly, It stores the memory location of the instructions to be executed, kinda like some lines of code are on screens when working on programs, NOT the ones from the full list of all avail. instructions from the CPU/MCU. EX:
10
20
30
etc,,,
Yes?

Line numbers like that are used in high-level languages like BASIC. This is because each BASIC instruction actually takes up many low-level machine instructions within the BASIC interpreter.

In assembly language, labels are used in place of actual memory locations that the PC holds. For example, $0300. So if my Z80 program starts at location $0100, I might have something like this:

    .ORG $0300
INITIO    LD A,$00
    OUT (LATCH),A
    LD A,(IODATA)
    OUT (CONTROL),A
    LD A,$00
    OUT (PORTB),A
    OUT (PORTC),A
    RET
IODATA    .BYTE $90            ;INIT DATA
    LD HL,LCDDATA
IOLOOP    CALL CHKBUSY
    LD A,(HL)
    OR A
    RET Z
    OUT (LCDI),A
    INC HL
    JP IOLOOP
LCDDATA    .BYTE $38,$08,$01,$06,$0C,$00    ;INIT DATA
    CALL CHKBUSY
    LD HL,CGDATA
    LD B,$10            ;BYTE COUNT
    LD C,$40            ;CG RAM ADDRESS
    LD A,C
    OUT (LCDI),A
    CALL CHKBUSY
    LD A,(HL)
    OUT (LCDD),A
    INC HL
    DEC B
    RET Z
    INC C
    LD A,C
    OUT (LCDI),A
    JP $0333
    .BYTE $11,$00,$04,$00,$11,$0E,$00,$00    ;CHARACTER 1 DATA
    .BYTE $11,$00,$04,$00,$0E,$11,$00,$00    ;CHARACTER 2 DATA
KNIGHT    LD HL,KDATA
    CALL PRINT
    RET
KDATA    .BYTE $0C,"PROGRAMMING COPYRIGHT 1994 CHRIS SAVAGE",$07,$00
RAMTEST    CALL LFEED
    LD HL,RAMDAT1
    CALL PRINT
    LD HL,RAMBOT
    LD BC,$0001
RAMLOOP    LD D,(HL)
    LD E,$AA            ;BIT PATTERN 1
    LD (HL),E
    LD A,(HL)
    CP E
    JP NZ,RAMFAIL
    LD E,$55            ;BIT PATTERN 2
    LD (HL),E
    LD A,(HL)
    CP E
    JP NZ,RAMFAIL
    LD (HL),D            ;RESTORE OLD DATA
    ADD HL,BC
    JP C,RAMPASS
    JP RAMLOOP
RAMPASS    SCF
    CCF
    LD BC,$8000
    SBC HL,BC
    LD ($A100),HL
    CALL DECIMAL
    LD HL,RAMDAT2
    CALL PRINT
    LD D,$08
    CALL DELAY3
    RET
RAMFAIL    CALL LFEED
    LD ($8100),HL
    LD HL,RAMDAT3
    CALL PRINT
    LD HL,($8100)
    LD ($A100),HL
    CALL DECIMAL
    LD HL,RAMDAT4
    CALL PRINT
    LD HL,($8100)
    LD ($A100),HL
    CALL HEX
    LD HL,RAMDAT5
    CALL PRINT
    DI
    JP $03F0            ;LOOP FOREVER (HALT)
RAMDAT1    .BYTE "TESTING RAM...",$00
RAMDAT2    .BYTE $20,"BYTES PASSED.",$00
RAMDAT3    .BYTE "RAM FAILURE AT LOCATION ",$00
RAMDAT4    .BYTE "  ($",$00
RAMDAT5    .BYTE ")",$00,$00
INITVAR    LD A,$00
    LD ($8000),A
    LD ($8001),A
    LD ($8002),A
    LD ($8008),A
    LD ($8009),A
    LD A,$FF
    LD ($8002),A
    LD HL,$0200
    LD ($8003),HL
    LD A,$06
    LD ($8005),A
    LD ($8006),A
    RET

Most older compilers make two passes when compiling...the first usually calculates the addresses for the labels, and the second converts the mnemonics into machine code.
I figured, but in yours starts $0300, so thinkning something like:
$0300 LD A $00
$0301 OUT (LATCH),A
$0302 LD A,(IODATA)
$0303 OUT (CONTROL),A
$etc..
 yes?

Chris Savage

#39
Quote from: JKnightandKARR on Nov 11, 2025, 02:39 PMI figured, but in yours starts $0300, so thinkning something like:
$0300 LD A $00
$0301 OUT (LATCH),A
$0302 LD A,(IODATA)
$0303 OUT (CONTROL),A
$etc..
 yes?

Unfortunately, no, because LD A, $00 takes up more than one byte of machine code.

When I have a moment, I will compile and save the LST file, which should have the addresses.

                    Bringing concepts to life through engineering.

Chris Savage

#40
The first column is the actual address in memory. The next few bytes are the machine code, followed by the ASM mnemonics. The first line is simply a directive telling the assembler where in memory this code should reside.

This should give you an idea of how stuff ends up in memory after assembly. The $20 are spaces as you can see in the byte blocks.

0000                          .ORG    0
0000 F3                      DI                    ; Disable interrupt
0001 31 FF FF                LD    SP,RAMTOP      ; Set stack pointer to top off ram
0004 ED 56                    IM    1              ; Set interrupt mode 1
0006 C3 00 01                JP    $100          ; jump to Start of program
0009           
0009 20 74 65 73              .byte " test system "  ; text string in rom
000D 74 20 73 79
0011 73 74 65 6D
0015 20
0016 20 56 20 31              .byte " V 1.00 "
001A 2E 30 30 20
001E 20 31 39 39              .byte " 1997 "
0022 37 20

P.S. - It may help to know that the constant, "RAMTOP" was set to $FFFF in a previous portion of this source code.

                    Bringing concepts to life through engineering.

JKnightandKARR

Quote from: Chris Savage on Nov 11, 2025, 02:48 PM
Quote from: JKnightandKARR on Nov 11, 2025, 02:39 PMI figured, but in yours starts $0300, so thinkning something like:
$0300 LD A $00
$0301 OUT (LATCH),A
$0302 LD A,(IODATA)
$0303 OUT (CONTROL),A
$etc..
 yes?

Unfortunately, no, because LD A, $00 takes up more than one byte of machine code.

When I have a moment, I will compile and save the LST file, which should have the addresses.
Got it, but generally speaking, they go in that order? from the first instruction being at/near $0300 down line by line to whatever the final address is, such as maybe $1254 for example, being the last one.

granz

Quote from: JKnightandKARR on Nov 11, 2025, 10:41 AMIf I understand the PC correctly, It stores the memory location of the instructions to be executed, kinda like some lines of code are on screens when working on programs, NOT the ones from the full list of all avail. instructions from the CPU/MCU. EX:
10
20
30
etc,,,
Yes?

You are actually putting way more complexity into this than it really is. The PC register is actually only a single memory location holding a single number (that is what a register really is.) That number, held in the PC register, is the address of the next single instruction in the program - not a list of future instructions.

The process of doing an instruction consists of two phases: the "fetch" phase, and the "operate" phase. In the fetch phase (page 14 - PDF file page 23) the processor will look at the PC register, and then take the number from that and put it onto the address bus, which will choose a single location in memory. The CardIAC model actually cheats a tiny bit, and shows the location in memory, rather than the address - so in running CardIAC, you skip the process of reading the PC register and placing that number onto the address bus; the PC register appears to actually address memory. The memory will put the single number that is in that location onto the data bus. The processor will take that (again) single number and put it into the instruction register. This is represented by the first box (right above the start) labelled "Instruction Register". The directions say to move the slides to "Move slides to agree with the contents of the bugs cell." This is the CardIAC equivalent of what I descried above.

Once the processor has placed the instruction number from memory in to the Instruction Register, the processor increments the PC register ("move the bug to the next location in memory") this keeps track of the location of the next instruction in your program. The processor then takes the steps (called microcode) from that number and performs those steps. You will see this when you build your own CardIAC - as you move the slide for the first digit of the number in memory it will change the commands in the "Instruction Decoder" at the top of the flow chart.

This is really the first rung on the ladder to becoming proficient in assembly language (and thus all other) programming. Ignore all the stuff about other registers (the second rung on that ladder) and addressing modes (the third rung) and everything else for now. Once you get to the first rung (that is all that CardIAC tries to get for you,) then you will be able to apply what you learn, and extend it to higher levels of assembly.

JKnightandKARR

Quote from: granz on Nov 12, 2025, 07:42 AM
Quote from: JKnightandKARR on Nov 11, 2025, 10:41 AMIf I understand the PC correctly, It stores the memory location of the instructions to be executed, kinda like some lines of code are on screens when working on programs, NOT the ones from the full list of all avail. instructions from the CPU/MCU. EX:
10
20
30
etc,,,
Yes?

You are actually putting way more complexity into this than it really is. The PC register is actually only a single memory location holding a single number (that is what a register really is.) That number, held in the PC register, is the address of the next single instruction in the program - not a list of future instructions.

The process of doing an instruction consists of two phases: the "fetch" phase, and the "operate" phase. In the fetch phase (page 14 - PDF file page 23) the processor will look at the PC register, and then take the number from that and put it onto the address bus, which will choose a single location in memory. The CardIAC model actually cheats a tiny bit, and shows the location in memory, rather than the address - so in running CardIAC, you skip the process of reading the PC register and placing that number onto the address bus; the PC register appears to actually address memory. The memory will put the single number that is in that location onto the data bus. The processor will take that (again) single number and put it into the instruction register. This is represented by the first box (right above the start) labelled "Instruction Register". The directions say to move the slides to "Move slides to agree with the contents of the bugs cell." This is the CardIAC equivalent of what I descried above.

Once the processor has placed the instruction number from memory in to the Instruction Register, the processor increments the PC register ("move the bug to the next location in memory") this keeps track of the location of the next instruction in your program. The processor then takes the steps (called microcode) from that number and performs those steps. You will see this when you build your own CardIAC - as you move the slide for the first digit of the number in memory it will change the commands in the "Instruction Decoder" at the top of the flow chart.

This is really the first rung on the ladder to becoming proficient in assembly language (and thus all other) programming. Ignore all the stuff about other registers (the second rung on that ladder) and addressing modes (the third rung) and everything else for now. Once you get to the first rung (that is all that CardIAC tries to get for you,) then you will be able to apply what you learn, and extend it to higher levels of assembly.
I got that from reading, now that I am not so tired the keyboard n screen looks strange. Lol. It incriments when finished with current inst i think, still ends up going through all the memory locations for the instructions on the program.

Chris Savage

Quote from: JKnightandKARR on Nov 13, 2025, 10:43 AMI got that from reading, now that I am not so tired the keyboard n screen looks strange. Lol. It incriments when finished with current inst i think, still ends up going through all the memory locations for the instructions on the program.

Well, it keeps executing instructions in a linear manner unless / until it hits a jump or branch. Were I familiar with this platform (Cardiac) I would write a short piece of code that explained it all easily.

                    Bringing concepts to life through engineering.