News:

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

Main Menu

Tiny BASIC? Perhaps not.

Started by Chris Savage, May 29, 2025, 09:33 PM

Previous topic - Next topic

Chris Savage

Object Code - Source

        I'm only responsible for what I say, not what you understand.

granz

Interesting, I could not find any further information (not even these pics) on this, even going to Cyber City Circuits web site. &H8400 seems pretty high in memory to start a BASIC, or any program. I also do not recognize this code, not even to where I could guess the CPU. Do you have any more info on this? Are you a member of BSKY, where you could ask them for more info (I'm too lazy to sign up right now.)

Chris Savage

#2
Quote from: granz on May 30, 2025, 06:55 AM&H8400 seems pretty high in memory to start a BASIC, or any program. I also do not recognize this code, not even to where I could guess the CPU. Do you have any more info on this? Are you a member of BSKY, where you could ask them for more info (I'm too lazy to sign up right now.)

So, as for the higher memory addresses, remember, many CPUs from back in the day jump to the end of memory to get their start address. The 6502, for example, jumps to a start vector toward the end of memory. $FFFC and $FFFD, IIRC. So if you put $00 @ $FFFC and $84 @ $FFFD, execution would begin at $8400. Typically in these systems, RAM was at the beginning of memory and often the stack pointer started at $0000.

The 6809 works exactly the same, but uses the vector addresses $FFFE / $FFFF. The Zilog Z80 starts executing instructions at $0000 on reset, which is what I prefer, but the first instruction could be a JP to any other address, which is almost what I do in my programs.

I say almost, because I do execute several instructions before jumping over the interrupt address space, which starts at $0038 (IRQ) and $0066 (NMI). There is code at each of these addresses for the interrupt routines. So my code starts off disabling interrupts, setting up the stack point to the end of RAM, CALLs a series or hardware initialization routines, then enables interrupts, before jumping to to actual start of the program, which is located at $0100 or higher, depending on the NMI code.

Quote from: granz on May 30, 2025, 06:55 AMInteresting, I could not find any further information (not even these pics) on this, even going to Cyber City Circuits web site.

Using Google Lens, I found the exact image in a post on Twitter, however, you can't see any content on Twitter unless you're signed in. As I no longer have an account there, I don't know if the poster provided any additional information. I will follow up on the Cyber City Circuits post and see if he knows which platform this is for.

        I'm only responsible for what I say, not what you understand.

granz

It turns out that this post:

was about the printout of a memory dump from some 1802 system (https://github.com/ruenahcmohr/1802BASIC/blob/main/1802BASIC.asm). They believe that it was from Tiny BASIC, but are not even certain of that. In attempting to disassemble the code, first it looks like they are missing about 8K of this code. Secondly, they have found some keywords from BASIC, but not all of them. The guy says "oh please let there be DATA support!" DATA is sometimes included in Tiny, but is often left out to lower the memory demands. They haven't even found any PRINT, or GOTO statements; those are pretty well necessary for any BASIC, even tiny. While they have found a RETURN, they have not been able to find the GOSUB - supporting the idea that they are missing some (much?) of the code for this language. I'm thinking that it may not actually be Tiny, but maybe a part of a more full-featured BASIC.

This is nothing more, really, than a playing around, trying to figure out what is being done here. They actually do mention that it is a strange place (&H8400, just above the middle of memory space) to find the beginning of code.

Back when Tiny was common, most systems had 8K, or less, ROM, and then 1-8K of RAM, hoping to add more RAM as the system grew. On the 1802 (which, like the Z-80, began operation at &H0000) the ROM would normally be at the beginning of memory space, followed by the RAM. RAM would normally be placed close to the end of ROM so that, as more RAM is added, the user could maximize their RAM. To start BASIC, or any language, that high in memory (if the ROM was a monitor rather than the language) would interrupt the RAM, and cut down on available usable RAM. That is why I was thinking that &H8400 was a strange place to put a BASIC.

Chris Savage

#4
Quote from: granz on May 30, 2025, 09:37 AMIt turns out that this post: was about the printout of a memory dump from some 1802 system

Well, shucks! Based on this new information, I have updated the title of the thread. LOL

Cyber City Circuits usually posts some informative stuff. I guess they got this one wrong. Thanks for digging. I hope you didn't get your fingernails too dirty.  ;D

P.S. - I asked Cyber City Circuits what platform this was from and the reply was, "Quest Super Elf"

        I'm only responsible for what I say, not what you understand.

granz

Quote from: Chris Savage on May 30, 2025, 09:44 AM
Quote from: granz on May 30, 2025, 09:37 AMIt turns out that this post: was about the printout of a memory dump from some 1802 system

Well, shucks! Based on this new information, I have updated the title of the thread. LOL

Cyber City Circuits usually posts some informative stuff. I guess they got this one wrong. Thanks for digging. I hope you didn't get your fingernails too dirty.  ;D

P.S. - I asked Cyber City Circuits what platform this was from and the reply was, "Quest Super Elf"
I'm not sure that they got this wrong, per se - it may have been a pretty well decked out Super Elf, and that they had loaded this code into the RAM of the Super Elf, in order to further examine the code in question. That would have placed the code higher in RAM, above whatever tools they were using (a monitor, disassembler, etc.) probably could have been sitting at &H8400.

Chris Savage

Quote from: granz on May 30, 2025, 12:47 PMI'm not sure that they got this wrong, per se - it may have been a pretty well decked out Super Elf, and that they had loaded this code into the RAM of the Super Elf, in order to further examine the code in question. That would have placed the code higher in RAM, above whatever tools they were using (a monitor, disassembler, etc.) probably could have been sitting at &H8400.

Well, I sure had fun running down that rabbit hole.  8)

        I'm only responsible for what I say, not what you understand.

granz

Yeah, it was kind of fun, I was thinking about beginning to hand disassemble a bit of the code, but I have too many other things on my plate at this time.

Chris Savage

Quote from: granz on May 30, 2025, 02:08 PMYeah, it was kind of fun, I was thinking about beginning to hand disassemble a bit of the code, but I have too many other things on my plate at this time.

Speaking of "hand-disassembling", here's a funny story...

Many years ago (1993?) I stopped using the Z80 in new designs. At the time I had so much "junk" around and I really couldn't afford the 60-drawer parts cabinets, so things were in boxes. I had a couple of dozen Z80s, peripheral chips, RAM, EPROMs, etc. I went onto the alt.electronics.? newsgroup and put it all up for sale. A HUGE box with all the parts to mess around with the Z80.

I regretted it. I kept wanting to mess around with it and didn't have the stuff. But worse, at some point the floppy diskette that had all my source files became corrupted and the backups were nowhere to be found. I had a large library of assembly code I wrote for my designs and it had specialized routines for LCD Modules, C= keyboards, etc.

One of my designs was built into a Commodore 64 computer enclosure which had the keyboard installed and used for the input. When I got rid of all my commodore stuff someone was looking for spare parts and I sent the case out in an original box without realizing my Z80 computer was still inside!!!

Some 5+ years later I was posting that I was looking for a C=64 keyboard to try and recreate one of my old computers and my buddy said he would send me one. The note said, "Here's the keyboard / enclosure you sent me years ago. I never ended up using it." When I opened it up, inside was my Z80 system with the EPROM still in the socket!!!

I spent some time hand-disassembling that code to get back my custom routines and somewhere at the house I have the original disassembly with the notes I added since I did the reverse engineering in two stages. One was running the disassembler on the code, the second step was isolating the individual subroutines, giving them back their original LABELS and making the code compatible with the assembler again.

When I get home later I will grab one of the intermediate files and post it so you can see what I mean. It was quite tedious, yet somehow fun. Many of the subroutines, especially those that did initialization, had data blocks to them which were coded after the return of the subroutine. This gave my code a small amount of protection as you would keep running into code that wasn't really code, but data for the routines.

        I'm only responsible for what I say, not what you understand.

granz

Quote from: Chris Savage on May 30, 2025, 03:12 PMSome 5+ years later I was posting that I was looking for a C=64 keyboard to try and recreate one of my old computers and my buddy said he would send me one. The note said, "Here's the keyboard / enclosure you sent me years ago. I never ended up using it." When I opened it up, inside was my Z80 system with the EPROM still in the socket!!!
YAY!!! I love it when a plan comes together!  That was great.

I also have a funny "hand disassembly" story: When I got my Sinclair ZX-80 put together, and was using it, I decided to hand disassemble the ROM. Using the BASIC's peek() function, I started (I don't remember whether I converted the decimal from BASIC to hex, or wrote a routine to do that into my "mini monitor.") It only took a short time, before I noticed a jump into the middle of another machine language command.  :o At that point I decided that I had made a mistake, and not noticed it, or that I had run into some kind of security that I was afraid that I would never figure out. No more disassembling the ZX-80 ROM for me! Although, I did later purchase one of those "xxx ROM revealed"-type books so that I could use the routines in the ROM.

Chris Savage

#10
Here is a screenshot I took some time ago of the Object Code loaded into my old programmer (that granz has now).

You cannot view this attachment.

As you can see, you're at $0300 through $03FF. Below is a literal translation as would be produced by a disassembler, which would not be able to tell the difference between code and data / text.

000300: ld      a,00h
        out    (04h),a
        ld      a,(0310h)
        out    (03h),a
        ld      a,00h
        out    (01h),a
        out    (02h),a
        ret   
        sub    b
000311: ld      hl,0320h
000314: call    04de
        ld      a,(hl)
        or      a
        ret    z
        out    (0ch),a
        inc    hl
        jp      0314
        jr      c,032a
        ld      bc,0c06h
        nop   
000326: call    04de
        ld      hl,0343h
        ld      b,10h
        ld      c,40h
        ld      a,c
        out    (0ch),a
000333: call    04de
        ld      a,(hl)
        out    (0dh),a
        inc    hl
        dec    b
        ret    z
        inc    c
        ld      a,c
        out    (0ch),a
        jp      0333
        ld      de,0400h
        nop   
        ld      de,000eh
        nop   
        ld      de,0400h
        nop   
        ld      c,11h
        nop   
        nop   
000353: ld      hl,035ah
        call    0457
        ret   
        inc    c
        ld      d,b
        ld      d,d
        ld      c,a
        ld      b,a
        ld      d,d
        ld      b,c
        ld      c,l
        ld      c,l
        ld      c,c
        ld      c,(hl)
        ld      b,a
        jr      nz,03ab
        ld      c,a
        ld      d,b
        ld      e,c
        ld      d,d
        ld      c,c
        ld      b,a
        ld      c,b
        ld      d,h
        jr      nz,03a3
        add    hl,sp
        add    hl,sp
        inc    (hl)
        jr      nz,03ba
        ld      c,b
        ld      d,d
        ld      c,c
        ld      d,e
        jr      nz,03d0
        ld      b,c
        ld      d,(hl)
        ld      b,c
        ld      b,a
        ld      b,l
        rlca   
        nop   
000384: call    04c3
        ld      hl,03f3h
        call    0457
        ld      hl,8000h
        ld      bc,0001h
000393: ld      d,(hl)
        ld      e,0aah
        ld      (hl),e
        ld      a,(hl)
        cp      e
        jp      nz,03c5
        ld      e,55h
        ld      (hl),e
        ld      a,(hl)
        cp      e
        jp      nz,03c5
        ld      (hl),d
        add    hl,bc
        jp      c,03ac
        jp      l0393
0003ac: scf   
        ccf   
        ld      bc,8000h
        sbc    hl,bc
        ld      (0a100h),hl
        call    052d
        ld      hl,0402h
        call    0457
        ld      d,08h
        call    06ee
        ret   
0003c5: call    04c3
        ld      (8100h),hl
        ld      hl,0411h
        call    0457
        ld      hl,(8100h)
        ld      (0a100h),hl
        call    052d
        ld      hl,042a
        call    0457
        ld      hl,(8100h)
        ld      (0a100h),hl
        call    05ef
        ld      hl,042fh
        call    0457
        di     
0003f0: jp      03f0
        ld      d,h
        ld      b,l
        ld      d,e
        ld      d,h
        ld      c,c
        ld      c,(hl)
        ld      b,a
        jr      nz,044e
        ld      b,c
        ld      c,l
        ld      l,2eh
        ld      l,00h
        jr      nz,0446
        ld      e,c
        ld      d,h
        ld      b,l
        ld      d,e
        jr      nz,045a
        ld      b,c

The translation is shown here first in RAW decoded form, then below that as I figured it out and added labels and variable names. Above, line #9 (sub b) is actually data for the subroutine right before it. Line #18 (jr c,032a) and several lines after that one are also data. In this case, LCD data (initialization).

    .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

It's important to note that, before sorting the code, some of it was previously decoded as instructions where data / text should have been. Until you step through it and decipher it, it's hard to make out what is what. I'm happy to say that I was successful in deciphering my old code. There's still a bit of work to do, but I have figured out what each section is and what parts are data / text.

You may notice there are a LOT of calls to $04DE, which in the bottom translation says, "CALL CHKBUSY". Every time you're going to write to a Hitachi-compatible LCD you should check the BUSY flag to see if the display is busy doing something. This call guarantees the display is ready to respond when a command / data is sent. On many systems, they simply put a delay in that spot. That is not efficient coding.


        I'm only responsible for what I say, not what you understand.

Chris Savage

@granz, so this is the exact code from that EPROM I recovered. Not the entire program...it was a 32KB EPROM, after all.

        I'm only responsible for what I say, not what you understand.

granz

Quote from: Chris Savage on Jun 03, 2025, 04:17 PM@granz, so this is the exact code from that EPROM I recovered. Not the entire program...it was a 32KB EPROM, after all.
Nice. So, were you able to disassemble (or find) the entire code? Do you remember the circuit that this was from?

Chris Savage

Quote from: granz on Jun 04, 2025, 07:34 AMSo, were you able to disassemble (or find) the entire code?

Sorry, what I meant was that I only posted a fraction of the code toward the beginning ($0300), since this was way too much data to put into code blocks in a post. I just wanted you to see how I originally decoded the object file and later how I formatted it out. Originally there were line numbers for every line, but then I realized it was making it harder for me to see blocks of code, so I removed many.

Also, in the formatted code, there are still some addresses that need to be converted into labels, but I haven't quite gotten back to this code yet. I am planning on sharing my code on the Z80 Retro Computer project as I work on that, since I will be using my old code for the new hardware.

Quote from: granz on Jun 04, 2025, 07:34 AMDo you remember the circuit that this was from?

Actually, yes, it was from the Z80 Control Board project (you never forget your first). When I finally created my first Z80 computer with keyboard input, LCD output, sound, etc. I created a wire-wrapped test system to test the interfaces and code to each piece of hardware.

My code (except the main application) is a series of subroutines, one after the next, called as their needed from within the main application. While this application was really just a series of menus and options to test various pieces of hardware, ALL the subroutines I had written were incorporated. So, while I didn't get anything important as far as one of my commercial applications, I did get a copy of ALL the subroutines I had written for the Z80 at that time.

There's a ROM Test subroutine, RAM Test routine, ISR setup routine, including vectored interrupts (not implemented in the test fixture, since nothing was driving those), Keyscan Routine and character mapping data for a C=16 8x8 matrix keyboard, including upper and lowercase character codes, piezo speaker output, backlight control and more.

The LCD section is set up such that you just set the HL register pair with the address of text and call the print routine. It can handle many special characters like CLS, HOME, BELL, CR, etc. When a BELL (CTRL-G) is encountered, it beeps the speaker. The LCD routine always calls the CHKBUSY routine to ensure the LCD is ready to receive. The test application counts from 0-65535 as fast as it can and displays that on the LCD to show how much faster a parallel LCD can be updated if you're using the busy flag to time writes.

Finally, there was a subroutine I wrote to display data on the LCD in decimal, hex or binary, with leading zero stripping that could be turned on / off with a flag.

        I'm only responsible for what I say, not what you understand.

granz

Quote from: Chris Savage on Jun 04, 2025, 07:53 AM...
My code (except the main application) is a series of subroutines, one after the next, called as their needed from within the main application. While this application was really just a series of menus and options to test various pieces of hardware, ALL the subroutines I had written were incorporated. So, while I didn't get anything important as far as one of my commercial applications, I did get a copy of ALL the subroutines I had written for the Z80 at that time.
...
That's great - sounds like you recovered a huge treasure, there. I don't even remember where any of my old code is stored, now.