02 June 2022, 12:51 | #1 |
Registered User
Join Date: Apr 2019
Location: UK
Posts: 172
|
Assembly language switch statement
I've written a bootblock trackdisk hunk loadfile loader as an exercise. The routine that iterates over the blocks really needs a (C/C++) switch statement. This is the best I could come up with in 68k - is there a more elegant way to implement this or is this the standard pattern? Thanks.
Code:
; --------------------------------------------------------------------------- ; Iterate over all the blocks in the file. ; A hunk file is just a set of blocks. ; Hunks are made of a number of blocks. ; See Amiga Guru Book section 22.1. ; ; Modifies: Lots! ; loadBlocks: moveq #0,d4 ; current byte offset into RootHunks array = currentIndex * sizeof(RootHunk) .blockLoop ; The total number of blocks in a load file is not known; The header contains the number of ; "root" hunks (CODE, DATA), but there may be other hunks e.g. RELOC hunks ; Just have to iterate over the binary to the end. move.l a5,d0 ; D0 <- readOffsetBytes ; TODO: assert(readOffsetBytes<=loadFileSizeBytes) cmp.l #loadFileSizeBytes,d0 ; set flags from readOffsetBytes-loadFileSizeBytes beq.b .end ; Z set if readOffsetBytes==loadFileSizeBytes ; Each block start with a longword identifier. ; ; Note that with the exception of the first hunk, HUNK_HEADER, only the lower 29 bits of the leading ID are used. ; The three most significant bits are used to indicate: ; (i) what type of memory to use for the hunk containing this block, and ; (ii) whether the block can be ignored ; ; Load modules will have a HUNK_HEADER block which contains the memory type to be used for each segment. ; Object modules do not contain a HUNK_HEADER block, and this information is not in the HUNK_UNIT either so ; it is packed into the block type ULONG ; See The AmigaDOS Manual - 3rd edition, p357 bsr.w readLongIntoD0 andi.l #$1fffffff,d0 ; strip top 3 bits just in case. D0 = blockType ; switch (blockType) TODO: Replace with jump table? cmpi.w #HUNK_CODE,d0 ; $3E9 bne.b .notHUNK_CODE pea .blockLoop(pc) ; push return address for RTS inside subsequent call bra.w loadHUNK_CODEorDATA ; use BRA instead of BSR so doesn't push return address .notHUNK_CODE cmpi.w #HUNK_DATA,d0 ; $3EA bne.b .notHUNK_DATA pea .blockLoop(pc) bra.w loadHUNK_CODEorDATA .notHUNK_DATA cmpi.w #HUNK_BSS,d0 ; $3EB bne.b .notHUNK_BSS pea .blockLoop(pc) bra.w loadHUNK_BSS .notHUNK_BSS cmpi.w #HUNK_RELOC32,d0 ; $3EC bne.b .notHUNK_RELOC32 pea .blockLoop(pc) bra.w processHUNK_RELOC32 .notHUNK_RELOC32 cmpi.w #HUNK_END,d0 ; $3F2 beq.b .blockLoop ; HUNK_END is just the longword identifer. Nothing to do ; Unhandled block type bra.w error .end rts |
02 June 2022, 14:00 | #2 |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
|
Personally, I like using a jump table like this:
Code:
; make sure to limit d0 to range of 0 to n before this code executes ; (where n = default in case of unhandled block type) ; if using 68020+ replace the add.w's with scaling *4 instead add.w d0,d0 add.w d0,d0 jmp .jmp_table(pc,d0.w) .jmp_table bra.w .notHUNK_CODE bra.w .notHUNK_DATA bra.w .notHUNK_BSS ; etc <<default case code>> .notHUNK_CODE <<do stuff>> |
02 June 2022, 15:07 | #3 |
68k
Join Date: Sep 2005
Location: Somewhere
Posts: 828
|
@hop
you can use something like that Code:
;in ; d0 - hunk value like $3e9,... Hunks: moveq #(end_table-table)/4-1,d2 lea (end_table,pc),a0 .loop move.l -(a0),d1 cmp.w d1,d0 bne.b .next swap d1 jmp (a0,d1.w) .next dbf d2,.loop ;handle unsupported hunk value here rts HUNK_CODE = $3e9 HUNK_DATA = $3ea table: dc.w doHunkCode-*,HUNK_CODE dc.w doHunkData-*,HUNK_DATA ;you can use dr.w doHunkCode,HUNK_CODE if your assembler supports it end_table doHunkCode: rts doHunkData: rts |
02 June 2022, 15:49 | #4 |
Registered User
Join Date: Jun 2016
Location: europe
Posts: 1,039
|
Also (several conditions, but in some cases they are all true), if there's only a small number of cmps to be made and/or you don't want to use a jmp table, and the numbers are close to each others, and you don't have to preserve them, you can do a sub and then chain subq/addq (shorter/faster) instead of a list of cmps.
And another thing, in Roondar's example (yup, that's how you typicallly do those things). Depending on your assembler, bra.w table can be problematic if you let it do optimizations because it can change (some of) them to 8-bit bra.b (or .s, depending on your style) and cause your code to explode. So, if you are considering that scenario, jmp offset(pc) is safer (same speed and instruction length). |
02 June 2022, 16:21 | #5 | |
Registered User
Join Date: Jul 2015
Location: The Netherlands
Posts: 3,411
|
Quote:
|
|
02 June 2022, 16:31 | #6 |
This cat is no more
Join Date: Dec 2004
Location: FRANCE
Age: 52
Posts: 8,200
|
Asman your method scans all values so complexity is O(n) whereas jump table complexity is O(1)
Better check for min/max then jump using jump table. |
02 June 2022, 16:32 | #7 |
Defendit numerus
Join Date: Mar 2017
Location: Crossing the Rubicon
Age: 53
Posts: 4,475
|
I'd do something like this:
Code:
include doshunks.i bsr readLongIntoD0 cmpi.w #HUNK_BREAK,d0 bhi.b unsupported_hunk subi.w #HUNK_UNIT,d0 bmi.b unsupported_hunk add.w d0,d0 move.w (hunk_j_table,pc,d0.w),d0 jmp (unsupported_hunk,pc,d0.w) ;or jsr (depending on your process_ code) hunk_j_table dc.w process_HUNK_UNIT-unsupported_hunk dc.w process_HUNK_NAME-unsupported_hunk dc.w process_HUNK_CODE-unsupported_hunk dc.w process_HUNK_DATA-unsupported_hunk dc.w process_HUNK_BSS-unsupported_hunk dc.w process_HUNK_RELOC32-unsupported_hunk dc.w process_HUNK_RELOC16-unsupported_hunk dc.w process_HUNK_RELOC8-unsupported_hunk dc.w process_HUNK_EXT-unsupported_hunk dc.w process_HUNK_SYMBOL-unsupported_hunk dc.w process_HUNK_DEBUG-unsupported_hunk dc.w process_HUNK_END-unsupported_hunk dc.w process_HUNK_HEADER-unsupported_hunk dc.w process_HUNK_OVERLAY-unsupported_hunk dc.w process_HUNK_BREAK-unsupported_hunk unsupported_hunk process_HUNK_UNIT process_HUNK_NAME process_HUNK_RELOC16 process_HUNK_RELOC8 process_HUNK_EXT process_HUNK_SYMBOL process_HUNK_DEBUG process_HUNK_OVERLAY process_HUNK_BREAK ; <<error or whatever>> process_HUNK_CODE process_HUNK_DATA ; <<relocatable hunk>> process_HUNK_BSS ; <<bss hunk>> process_HUNK_RELOC32 ; <<reloc table>> process_HUNK_END ; <<end exe>> process_HUNK_HEADER ; .... |
02 June 2022, 17:00 | #8 |
68k
Join Date: Sep 2005
Location: Somewhere
Posts: 828
|
@jotd
Yes, this is just example how to handle switch in other way than spagetti code of cmp/bcc. |
02 June 2022, 23:20 | #9 |
Registered User
Join Date: Apr 2019
Location: UK
Posts: 172
|
Thanks. I'll try some of these out.
|
03 June 2022, 12:16 | #10 |
Registered User
Join Date: Apr 2019
Location: UK
Posts: 172
|
|
Currently Active Users Viewing This Thread: 1 (0 members and 1 guests) | |
Thread Tools | |
Similar Threads | ||||
Thread | Thread Starter | Forum | Replies | Last Post |
Fast switch statement code | Jobbo | Coders. Asm / Hardware | 10 | 22 October 2021 19:13 |
MC68000 Assembly Language Support | apex | Coders. Asm / Hardware | 1 | 06 August 2021 19:16 |
for..each statement in CLI | pieter1976 | support.Other | 10 | 09 January 2020 22:15 |
A1200 and assembly language | aricz | Coders. General | 16 | 08 February 2011 12:31 |
HELP with german language and installation of a aga-rtg switch by Multimedia Design | keropi | support.Hardware | 9 | 05 January 2006 22:41 |
|
|